Merge branch 'master' into master
This commit is contained in:
commit
2a0150cbbb
191 changed files with 11189 additions and 11970 deletions
2
.gitmodules
vendored
2
.gitmodules
vendored
|
@ -1,6 +1,6 @@
|
||||||
[submodule "lwip/lwip"]
|
[submodule "lwip/lwip"]
|
||||||
path = lwip/lwip
|
path = lwip/lwip
|
||||||
url = https://github.com/SuperHouse/esp-lwip.git
|
url = https://github.com/ourairquality/lwip.git
|
||||||
[submodule "extras/mbedtls/mbedtls"]
|
[submodule "extras/mbedtls/mbedtls"]
|
||||||
path = extras/mbedtls/mbedtls
|
path = extras/mbedtls/mbedtls
|
||||||
url = https://github.com/ARMmbed/mbedtls.git
|
url = https://github.com/ARMmbed/mbedtls.git
|
||||||
|
|
|
@ -1,65 +1,61 @@
|
||||||
The FreeRTOS.org source code is licensed by the *modified* GNU General Public
|
The FreeRTOS open source license covers the FreeRTOS source files,
|
||||||
License (GPL), text provided below. A special exception to the GPL is
|
which are located in the /FreeRTOS/Source directory of the official FreeRTOS
|
||||||
included to allow you to distribute a combined work that includes FreeRTOS
|
download. It also covers most of the source files in the demo application
|
||||||
without being obliged to provide the source code for any proprietary
|
projects, which are located in the /FreeRTOS/Demo directory of the official
|
||||||
components. See the licensing section of http://www.FreeRTOS.org for full
|
FreeRTOS download. The demo projects may also include third party software that
|
||||||
details. The exception text is also included at the bottom of this file.
|
is not part of FreeRTOS and is licensed separately to FreeRTOS. Examples of
|
||||||
|
third party software includes header files provided by chip or tools vendors,
|
||||||
|
linker scripts, peripheral drivers, etc. All the software in subdirectories of
|
||||||
|
the /FreeRTOS directory is either open source or distributed with permission,
|
||||||
|
and is free for use. For the avoidance of doubt, refer to the comments at the
|
||||||
|
top of each source file.
|
||||||
|
|
||||||
The FreeRTOS download also includes demo application source code, some of
|
----------------------------------------------------------------------------
|
||||||
which is provided by third parties AND IS LICENSED SEPARATELY FROM FREERTOS.
|
|
||||||
|
|
||||||
For the avoidance of any doubt refer to the comment included at the top
|
NOTE: The modification to the GPL is included to allow you to distribute a
|
||||||
of each source and header file for license and copyright information.
|
combined work that includes FreeRTOS without being obliged to provide the source
|
||||||
|
code for proprietary components.
|
||||||
|
|
||||||
This is a list of files for which Real Time Engineers Ltd are not the
|
----------------------------------------------------------------------------
|
||||||
copyright owner and are NOT COVERED BY THE GPL.
|
|
||||||
|
Applying to FreeRTOS V8.2.3 up to the latest version, the FreeRTOS GPL Exception
|
||||||
|
Text follows:
|
||||||
|
|
||||||
|
Any FreeRTOS *source code*, whether modified or in it's original release form,
|
||||||
|
or whether in whole or in part, can only be distributed by you under the terms
|
||||||
|
of the GNU General Public License plus this exception. An independent module is
|
||||||
|
a module which is not derived from or based on FreeRTOS.
|
||||||
|
|
||||||
|
Clause 1:
|
||||||
|
|
||||||
|
Linking FreeRTOS with other modules is making a combined work based on FreeRTOS.
|
||||||
|
Thus, the terms and conditions of the GNU General Public License V2 cover the
|
||||||
|
whole combination.
|
||||||
|
|
||||||
|
As a special exception, the copyright holders of FreeRTOS give you permission to
|
||||||
|
link FreeRTOS with independent modules to produce a statically linked
|
||||||
|
executable, regardless of the license terms of these independent modules, and to
|
||||||
|
copy and distribute the resulting executable under terms of your choice,
|
||||||
|
provided that you also meet, for each linked independent module, the terms and
|
||||||
|
conditions of the license of that module. An independent module is a module
|
||||||
|
which is not derived from or based on FreeRTOS.
|
||||||
|
|
||||||
|
Clause 2:
|
||||||
|
|
||||||
|
FreeRTOS may not be used for any competitive or comparative purpose, including
|
||||||
|
the publication of any form of run time or compile time metric, without the
|
||||||
|
express permission of Real Time Engineers Ltd. (this is the norm within the
|
||||||
|
industry and is intended to ensure information accuracy).
|
||||||
|
|
||||||
|
|
||||||
1) Various header files provided by silicon manufacturers and tool vendors
|
|
||||||
that define processor specific memory addresses and utility macros.
|
|
||||||
Permission has been granted by the various copyright holders for these
|
|
||||||
files to be included in the FreeRTOS download. Users must ensure license
|
|
||||||
conditions are adhered to for any use other than compilation of the
|
|
||||||
FreeRTOS demo applications.
|
|
||||||
|
|
||||||
2) The uIP TCP/IP stack the copyright of which is held by Adam Dunkels.
|
|
||||||
Users must ensure the open source license conditions stated at the top
|
|
||||||
of each uIP source file is understood and adhered to.
|
|
||||||
|
|
||||||
3) The lwIP TCP/IP stack the copyright of which is held by the Swedish
|
|
||||||
Institute of Computer Science. Users must ensure the open source license
|
|
||||||
conditions stated at the top of each lwIP source file is understood and
|
|
||||||
adhered to.
|
|
||||||
|
|
||||||
4) Various peripheral driver source files and binaries provided by silicon
|
|
||||||
manufacturers and tool vendors. Permission has been granted by the
|
|
||||||
various copyright holders for these files to be included in the FreeRTOS
|
|
||||||
download. Users must ensure license conditions are adhered to for any
|
|
||||||
use other than compilation of the FreeRTOS demo applications.
|
|
||||||
|
|
||||||
5) The files contained within FreeRTOS\Demo\WizNET_DEMO_TERN_186\tern_code,
|
|
||||||
which are slightly modified versions of code provided by and copyright to
|
|
||||||
Tern Inc.
|
|
||||||
|
|
||||||
Errors and omissions should be reported to Richard Barry, contact details for
|
|
||||||
whom can be obtained from http://www.FreeRTOS.org.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The GPL license text follows.
|
|
||||||
|
|
||||||
A special exception to the GPL is included to allow you to distribute a
|
|
||||||
combined work that includes FreeRTOS without being obliged to provide
|
|
||||||
the source code for any proprietary components. See the licensing section
|
|
||||||
of http://www.FreeRTOS.org for full details. The exception text is also
|
|
||||||
included at the bottom of this file.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
--------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
The standard GPL V2 text:
|
||||||
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
GNU GENERAL PUBLIC LICENSE
|
||||||
Version 2, June 1991
|
Version 2, June 1991
|
||||||
|
|
||||||
|
@ -401,40 +397,3 @@ consider it more useful to permit linking proprietary applications with the
|
||||||
library. If this is what you want to do, use the GNU Library General
|
library. If this is what you want to do, use the GNU Library General
|
||||||
Public License instead of this License.
|
Public License instead of this License.
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
The FreeRTOS GPL Exception Text:
|
|
||||||
|
|
||||||
Any FreeRTOS source code, whether modified or in it's original release form,
|
|
||||||
or whether in whole or in part, can only be distributed by you under the terms
|
|
||||||
of the GNU General Public License plus this exception. An independent module is
|
|
||||||
a module which is not derived from or based on FreeRTOS.
|
|
||||||
|
|
||||||
Clause 1:
|
|
||||||
|
|
||||||
Linking FreeRTOS statically or dynamically with other modules is making a
|
|
||||||
combined work based on FreeRTOS. Thus, the terms and conditions of the GNU
|
|
||||||
General Public License cover the whole combination.
|
|
||||||
|
|
||||||
As a special exception, the copyright holder of FreeRTOS gives you permission
|
|
||||||
to link FreeRTOS with independent modules that communicate with FreeRTOS
|
|
||||||
solely through the FreeRTOS API interface, regardless of the license terms of
|
|
||||||
these independent modules, and to copy and distribute the resulting combined
|
|
||||||
work under terms of your choice, provided that
|
|
||||||
|
|
||||||
+ Every copy of the combined work is accompanied by a written statement that
|
|
||||||
details to the recipient the version of FreeRTOS used and an offer by yourself
|
|
||||||
to provide the FreeRTOS source code (including any modifications you may have
|
|
||||||
made) should the recipient request it.
|
|
||||||
|
|
||||||
+ The combined work is not itself an RTOS, scheduler, kernel or related product.
|
|
||||||
|
|
||||||
+ The independent modules add significant and primary functionality to FreeRTOS
|
|
||||||
and do not merely extend the existing functionality already present in FreeRTOS.
|
|
||||||
|
|
||||||
Clause 2:
|
|
||||||
|
|
||||||
FreeRTOS may not be used for any competitive or comparative purpose, including the
|
|
||||||
publication of any form of run time or compile time metric, without the express
|
|
||||||
permission of Real Time Engineers Ltd. (this is the norm within the industry and
|
|
||||||
is intended to ensure information accuracy).
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -139,6 +139,16 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co
|
||||||
/* A StaticEventGroup_t object must be provided. */
|
/* A StaticEventGroup_t object must be provided. */
|
||||||
configASSERT( pxEventGroupBuffer );
|
configASSERT( pxEventGroupBuffer );
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
{
|
||||||
|
/* Sanity check that the size of the structure used to declare a
|
||||||
|
variable of type StaticEventGroup_t equals the size of the real
|
||||||
|
event group structure. */
|
||||||
|
volatile size_t xSize = sizeof( StaticEventGroup_t );
|
||||||
|
configASSERT( xSize == sizeof( EventGroup_t ) );
|
||||||
|
}
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
/* The user has provided a statically allocated event group - use it. */
|
/* The user has provided a statically allocated event group - use it. */
|
||||||
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
|
pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */
|
||||||
|
|
||||||
|
@ -602,7 +612,7 @@ BaseType_t xMatchFound = pdFALSE;
|
||||||
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
|
eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows
|
||||||
that is was unblocked due to its required bits matching, rather
|
that is was unblocked due to its required bits matching, rather
|
||||||
than because it timed out. */
|
than because it timed out. */
|
||||||
( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
|
vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move onto the next list item. Note pxListItem->pxNext is not
|
/* Move onto the next list item. Note pxListItem->pxNext is not
|
||||||
|
@ -633,9 +643,9 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
|
||||||
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
/* Unblock the task, returning 0 as the event list is being deleted
|
/* Unblock the task, returning 0 as the event list is being deleted
|
||||||
and cannot therefore have any bits set. */
|
and cannot therefore have any bits set. */
|
||||||
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) );
|
||||||
( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) )
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -126,6 +126,10 @@ extern "C" {
|
||||||
#error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details.
|
#error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if configMAX_PRIORITIES < 1
|
||||||
|
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef configUSE_PREEMPTION
|
#ifndef configUSE_PREEMPTION
|
||||||
#error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
|
#error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
|
||||||
#endif
|
#endif
|
||||||
|
@ -142,10 +146,6 @@ extern "C" {
|
||||||
#error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
|
#error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef configMAX_PRIORITIES
|
|
||||||
#error configMAX_PRIORITIES must be defined to be greater than or equal to 1.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef configUSE_CO_ROUTINES
|
#ifndef configUSE_CO_ROUTINES
|
||||||
#define configUSE_CO_ROUTINES 0
|
#define configUSE_CO_ROUTINES 0
|
||||||
#endif
|
#endif
|
||||||
|
@ -408,6 +408,14 @@ extern "C" {
|
||||||
#define configCHECK_FOR_STACK_OVERFLOW 0
|
#define configCHECK_FOR_STACK_OVERFLOW 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configRECORD_STACK_HIGH_ADDRESS
|
||||||
|
#define configRECORD_STACK_HIGH_ADDRESS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H
|
||||||
|
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The following event macros are embedded in the kernel API calls. */
|
/* The following event macros are embedded in the kernel API calls. */
|
||||||
|
|
||||||
#ifndef traceMOVED_TASK_TO_READY_STATE
|
#ifndef traceMOVED_TASK_TO_READY_STATE
|
||||||
|
@ -708,6 +716,10 @@ extern "C" {
|
||||||
#define configUSE_TICKLESS_IDLE 0
|
#define configUSE_TICKLESS_IDLE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING
|
||||||
|
#define configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( x )
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef configPRE_SLEEP_PROCESSING
|
#ifndef configPRE_SLEEP_PROCESSING
|
||||||
#define configPRE_SLEEP_PROCESSING( x )
|
#define configPRE_SLEEP_PROCESSING( x )
|
||||||
#endif
|
#endif
|
||||||
|
@ -724,6 +736,10 @@ extern "C" {
|
||||||
#define portTASK_USES_FLOATING_POINT()
|
#define portTASK_USES_FLOATING_POINT()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef portTASK_CALLS_SECURE_FUNCTIONS
|
||||||
|
#define portTASK_CALLS_SECURE_FUNCTIONS()
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef configUSE_TIME_SLICING
|
#ifndef configUSE_TIME_SLICING
|
||||||
#define configUSE_TIME_SLICING 1
|
#define configUSE_TIME_SLICING 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -782,6 +798,12 @@ extern "C" {
|
||||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configSTACK_DEPTH_TYPE
|
||||||
|
/* Defaults to uint16_t for backward compatibility, but can be overridden
|
||||||
|
in FreeRTOSConfig.h if uint16_t is too restrictive. */
|
||||||
|
#define configSTACK_DEPTH_TYPE uint16_t
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Sanity check the configuration. */
|
/* Sanity check the configuration. */
|
||||||
#if( configUSE_TICKLESS_IDLE != 0 )
|
#if( configUSE_TICKLESS_IDLE != 0 )
|
||||||
#if( INCLUDE_vTaskSuspend != 1 )
|
#if( INCLUDE_vTaskSuspend != 1 )
|
||||||
|
@ -797,6 +819,10 @@ extern "C" {
|
||||||
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
|
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configINITIAL_TICK_COUNT
|
||||||
|
#define configINITIAL_TICK_COUNT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if( portTICK_TYPE_IS_ATOMIC == 0 )
|
#if( portTICK_TYPE_IS_ATOMIC == 0 )
|
||||||
/* Either variables of tick type cannot be read atomically, or
|
/* Either variables of tick type cannot be read atomically, or
|
||||||
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
|
portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when
|
||||||
|
@ -917,7 +943,7 @@ typedef struct xSTATIC_TCB
|
||||||
UBaseType_t uxDummy5;
|
UBaseType_t uxDummy5;
|
||||||
void *pxDummy6;
|
void *pxDummy6;
|
||||||
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
|
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
|
||||||
#if ( portSTACK_GROWTH > 0 )
|
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||||
void *pxDummy8;
|
void *pxDummy8;
|
||||||
#endif
|
#endif
|
||||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||||
|
@ -945,10 +971,14 @@ typedef struct xSTATIC_TCB
|
||||||
uint32_t ulDummy18;
|
uint32_t ulDummy18;
|
||||||
uint8_t ucDummy19;
|
uint8_t ucDummy19;
|
||||||
#endif
|
#endif
|
||||||
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
#if( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
|
||||||
uint8_t uxDummy20;
|
uint8_t uxDummy20;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
|
uint8_t ucDummy21;
|
||||||
|
#endif
|
||||||
|
|
||||||
} StaticTask_t;
|
} StaticTask_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,15 +1,38 @@
|
||||||
/* Default esp-open-sdk FreeRTOSConfig file.
|
/*
|
||||||
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
You can override settings in here by creating your own
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
FreeRTOSConfig.h file in your program directory.
|
|
||||||
|
|
||||||
You could just copy this file there and edit it, but it's
|
This file is part of the FreeRTOS distribution.
|
||||||
recommended you instead define whatever you want to override and
|
|
||||||
then use #include_next<FreeRTOSConfig.h> to pick up these defaults.
|
|
||||||
|
|
||||||
The "blink" example in "examples/blink" provides an example of how
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||||
to do this.
|
the terms of the GNU General Public License (version 2) as published by the
|
||||||
|
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||||
|
|
||||||
|
***************************************************************************
|
||||||
|
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||||
|
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||||
|
>>! obliged to provide the source code for proprietary components !<<
|
||||||
|
>>! outside of the FreeRTOS kernel. !<<
|
||||||
|
***************************************************************************
|
||||||
|
|
||||||
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||||
|
link: http://www.freertos.org/a00114.html
|
||||||
|
|
||||||
|
|
||||||
|
For esp-open-rtos, you can override settings in here by creating your own
|
||||||
|
FreeRTOSConfig.h file in your program directory. You could just copy this
|
||||||
|
file there and edit it, but it's recommended you instead define whatever you
|
||||||
|
want to override and then use #include_next<FreeRTOSConfig.h> to pick up
|
||||||
|
these defaults. The "blink" example in "examples/blink" provides an example
|
||||||
|
of how to do this.
|
||||||
|
|
||||||
|
1 tab == 4 spaces!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __DEFAULT_FREERTOS_CONFIG_H
|
#ifndef __DEFAULT_FREERTOS_CONFIG_H
|
||||||
#define __DEFAULT_FREERTOS_CONFIG_H
|
#define __DEFAULT_FREERTOS_CONFIG_H
|
||||||
|
|
||||||
|
@ -20,7 +43,7 @@
|
||||||
* application requirements.
|
* application requirements.
|
||||||
*
|
*
|
||||||
* THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE
|
* 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.
|
* See http://www.freertos.org/a00110.html.
|
||||||
*----------------------------------------------------------*/
|
*----------------------------------------------------------*/
|
||||||
|
@ -47,7 +70,7 @@
|
||||||
#define configTICK_RATE_HZ ( ( TickType_t ) 100 )
|
#define configTICK_RATE_HZ ( ( TickType_t ) 100 )
|
||||||
#endif
|
#endif
|
||||||
#ifndef configMAX_PRIORITIES
|
#ifndef configMAX_PRIORITIES
|
||||||
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 15 )
|
#define configMAX_PRIORITIES ( 15 )
|
||||||
#endif
|
#endif
|
||||||
#ifndef configMINIMAL_STACK_SIZE
|
#ifndef configMINIMAL_STACK_SIZE
|
||||||
#define configMINIMAL_STACK_SIZE ( ( unsigned short )256 )
|
#define configMINIMAL_STACK_SIZE ( ( unsigned short )256 )
|
||||||
|
@ -108,6 +131,10 @@
|
||||||
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef configUSE_NEWLIB_REENTRANT
|
||||||
|
#define configUSE_NEWLIB_REENTRANT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Set the following definitions to 1 to include the API function, or zero
|
/* Set the following definitions to 1 to include the API function, or zero
|
||||||
to exclude the API function. */
|
to exclude the API function. */
|
||||||
#ifndef INCLUDE_vTaskPrioritySet
|
#ifndef INCLUDE_vTaskPrioritySet
|
||||||
|
@ -144,5 +171,10 @@ to exclude the API function. */
|
||||||
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
#define configENABLE_BACKWARD_COMPATIBILITY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Normal assert() semantics without relying on the provision of an assert.h
|
||||||
|
header file. */
|
||||||
|
void vAssertCalled(const char * pcFile, unsigned long ulLine);
|
||||||
|
#define configASSERT(x) if((x) == 0) vAssertCalled(__FILE__, __LINE__);
|
||||||
|
|
||||||
#endif /* __DEFAULT_FREERTOS_CONFIG_H */
|
#endif /* __DEFAULT_FREERTOS_CONFIG_H */
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -205,7 +205,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t;
|
||||||
typedef struct xLIST
|
typedef struct xLIST
|
||||||
{
|
{
|
||||||
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
configLIST_VOLATILE UBaseType_t uxNumberOfItems;
|
volatile UBaseType_t uxNumberOfItems;
|
||||||
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
|
||||||
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
|
||||||
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -83,6 +83,7 @@
|
||||||
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask );
|
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask );
|
||||||
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer );
|
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer );
|
||||||
BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
|
BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
|
||||||
|
BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
|
||||||
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
|
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
|
||||||
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
|
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
|
||||||
void MPU_vTaskDelay( const TickType_t xTicksToDelay );
|
void MPU_vTaskDelay( const TickType_t xTicksToDelay );
|
||||||
|
@ -124,7 +125,9 @@ BaseType_t MPU_xTaskGetSchedulerState( void );
|
||||||
|
|
||||||
/* MPU versions of queue.h API function. */
|
/* MPU versions of queue.h API function. */
|
||||||
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition );
|
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition );
|
||||||
BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek );
|
BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
|
||||||
|
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
|
||||||
|
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait );
|
||||||
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue );
|
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue );
|
||||||
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
|
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
|
||||||
void MPU_vQueueDelete( QueueHandle_t xQueue );
|
void MPU_vQueueDelete( QueueHandle_t xQueue );
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -130,7 +130,9 @@ only for ports that are using the MPU. */
|
||||||
|
|
||||||
/* Map standard queue.h API functions to the MPU equivalents. */
|
/* Map standard queue.h API functions to the MPU equivalents. */
|
||||||
#define xQueueGenericSend MPU_xQueueGenericSend
|
#define xQueueGenericSend MPU_xQueueGenericSend
|
||||||
#define xQueueGenericReceive MPU_xQueueGenericReceive
|
#define xQueueReceive MPU_xQueueReceive
|
||||||
|
#define xQueuePeek MPU_xQueuePeek
|
||||||
|
#define xQueueSemaphoreTake MPU_xQueueSemaphoreTake
|
||||||
#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
|
#define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting
|
||||||
#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
|
#define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable
|
||||||
#define vQueueDelete MPU_vQueueDelete
|
#define vQueueDelete MPU_vQueueDelete
|
||||||
|
@ -177,8 +179,11 @@ only for ports that are using the MPU. */
|
||||||
#define xEventGroupSync MPU_xEventGroupSync
|
#define xEventGroupSync MPU_xEventGroupSync
|
||||||
#define vEventGroupDelete MPU_vEventGroupDelete
|
#define vEventGroupDelete MPU_vEventGroupDelete
|
||||||
|
|
||||||
/* Remove the privileged function macro. */
|
/* Remove the privileged function macro, but keep the PRIVILEGED_DATA
|
||||||
|
macro so applications can place data in privileged access sections
|
||||||
|
(useful when using statically allocated objects). */
|
||||||
#define PRIVILEGED_FUNCTION
|
#define PRIVILEGED_FUNCTION
|
||||||
|
#define PRIVILEGED_DATA __attribute__((section("privileged_data")))
|
||||||
|
|
||||||
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
|
#else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -696,12 +696,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ
|
||||||
* <pre>
|
* <pre>
|
||||||
BaseType_t xQueuePeek(
|
BaseType_t xQueuePeek(
|
||||||
QueueHandle_t xQueue,
|
QueueHandle_t xQueue,
|
||||||
void *pvBuffer,
|
void * const pvBuffer,
|
||||||
TickType_t xTicksToWait
|
TickType_t xTicksToWait
|
||||||
);</pre>
|
);</pre>
|
||||||
*
|
*
|
||||||
* This is a macro that calls the xQueueGenericReceive() function.
|
|
||||||
*
|
|
||||||
* Receive an item from a queue without removing the item from the queue.
|
* Receive an item from a queue without removing the item from the queue.
|
||||||
* The item is received by copy so a buffer of adequate size must be
|
* The item is received by copy so a buffer of adequate size must be
|
||||||
* provided. The number of bytes copied into the buffer was defined when
|
* provided. The number of bytes copied into the buffer was defined when
|
||||||
|
@ -782,10 +780,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ
|
||||||
// ... Rest of task code.
|
// ... Rest of task code.
|
||||||
}
|
}
|
||||||
</pre>
|
</pre>
|
||||||
* \defgroup xQueueReceive xQueueReceive
|
* \defgroup xQueuePeek xQueuePeek
|
||||||
* \ingroup QueueManagement
|
* \ingroup QueueManagement
|
||||||
*/
|
*/
|
||||||
#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE )
|
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* queue. h
|
* queue. h
|
||||||
|
@ -829,8 +827,6 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV
|
||||||
TickType_t xTicksToWait
|
TickType_t xTicksToWait
|
||||||
);</pre>
|
);</pre>
|
||||||
*
|
*
|
||||||
* This is a macro that calls the xQueueGenericReceive() function.
|
|
||||||
*
|
|
||||||
* Receive an item from a queue. The item is received by copy so a buffer of
|
* Receive an item from a queue. The item is received by copy so a buffer of
|
||||||
* adequate size must be provided. The number of bytes copied into the buffer
|
* adequate size must be provided. The number of bytes copied into the buffer
|
||||||
* was defined when the queue was created.
|
* was defined when the queue was created.
|
||||||
|
@ -911,106 +907,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV
|
||||||
* \defgroup xQueueReceive xQueueReceive
|
* \defgroup xQueueReceive xQueueReceive
|
||||||
* \ingroup QueueManagement
|
* \ingroup QueueManagement
|
||||||
*/
|
*/
|
||||||
#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE )
|
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* queue. h
|
|
||||||
* <pre>
|
|
||||||
BaseType_t xQueueGenericReceive(
|
|
||||||
QueueHandle_t xQueue,
|
|
||||||
void *pvBuffer,
|
|
||||||
TickType_t xTicksToWait
|
|
||||||
BaseType_t xJustPeek
|
|
||||||
);</pre>
|
|
||||||
*
|
|
||||||
* It is preferred that the macro xQueueReceive() be used rather than calling
|
|
||||||
* this function directly.
|
|
||||||
*
|
|
||||||
* Receive an item from a queue. The item is received by copy so a buffer of
|
|
||||||
* adequate size must be provided. The number of bytes copied into the buffer
|
|
||||||
* was defined when the queue was created.
|
|
||||||
*
|
|
||||||
* This function must not be used in an interrupt service routine. See
|
|
||||||
* xQueueReceiveFromISR for an alternative that can.
|
|
||||||
*
|
|
||||||
* @param xQueue The handle to the queue from which the item is to be
|
|
||||||
* received.
|
|
||||||
*
|
|
||||||
* @param pvBuffer Pointer to the buffer into which the received item will
|
|
||||||
* be copied.
|
|
||||||
*
|
|
||||||
* @param xTicksToWait The maximum amount of time the task should block
|
|
||||||
* waiting for an item to receive should the queue be empty at the time
|
|
||||||
* of the call. The time is defined in tick periods so the constant
|
|
||||||
* portTICK_PERIOD_MS should be used to convert to real time if this is required.
|
|
||||||
* xQueueGenericReceive() will return immediately if the queue is empty and
|
|
||||||
* xTicksToWait is 0.
|
|
||||||
*
|
|
||||||
* @param xJustPeek When set to true, the item received from the queue is not
|
|
||||||
* actually removed from the queue - meaning a subsequent call to
|
|
||||||
* xQueueReceive() will return the same item. When set to false, the item
|
|
||||||
* being received from the queue is also removed from the queue.
|
|
||||||
*
|
|
||||||
* @return pdTRUE if an item was successfully received from the queue,
|
|
||||||
* otherwise pdFALSE.
|
|
||||||
*
|
|
||||||
* Example usage:
|
|
||||||
<pre>
|
|
||||||
struct AMessage
|
|
||||||
{
|
|
||||||
char ucMessageID;
|
|
||||||
char ucData[ 20 ];
|
|
||||||
} xMessage;
|
|
||||||
|
|
||||||
QueueHandle_t xQueue;
|
|
||||||
|
|
||||||
// Task to create a queue and post a value.
|
|
||||||
void vATask( void *pvParameters )
|
|
||||||
{
|
|
||||||
struct AMessage *pxMessage;
|
|
||||||
|
|
||||||
// Create a queue capable of containing 10 pointers to AMessage structures.
|
|
||||||
// These should be passed by pointer as they contain a lot of data.
|
|
||||||
xQueue = xQueueCreate( 10, sizeof( struct AMessage * ) );
|
|
||||||
if( xQueue == 0 )
|
|
||||||
{
|
|
||||||
// Failed to create the queue.
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...
|
|
||||||
|
|
||||||
// Send a pointer to a struct AMessage object. Don't block if the
|
|
||||||
// queue is already full.
|
|
||||||
pxMessage = & xMessage;
|
|
||||||
xQueueSend( xQueue, ( void * ) &pxMessage, ( TickType_t ) 0 );
|
|
||||||
|
|
||||||
// ... Rest of task code.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Task to receive from the queue.
|
|
||||||
void vADifferentTask( void *pvParameters )
|
|
||||||
{
|
|
||||||
struct AMessage *pxRxedMessage;
|
|
||||||
|
|
||||||
if( xQueue != 0 )
|
|
||||||
{
|
|
||||||
// Receive a message on the created queue. Block for 10 ticks if a
|
|
||||||
// message is not immediately available.
|
|
||||||
if( xQueueGenericReceive( xQueue, &( pxRxedMessage ), ( TickType_t ) 10 ) )
|
|
||||||
{
|
|
||||||
// pcRxedMessage now points to the struct AMessage variable posted
|
|
||||||
// by vATask.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... Rest of task code.
|
|
||||||
}
|
|
||||||
</pre>
|
|
||||||
* \defgroup xQueueReceive xQueueReceive
|
|
||||||
* \ingroup QueueManagement
|
|
||||||
*/
|
|
||||||
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ) PRIVILEGED_FUNCTION;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* queue. h
|
* queue. h
|
||||||
|
@ -1560,7 +1457,9 @@ QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION
|
||||||
QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
|
QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
|
||||||
QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION;
|
QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION;
|
||||||
QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
|
QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION;
|
||||||
|
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
|
||||||
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
||||||
|
void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For internal use only. Use xSemaphoreTakeMutexRecursive() or
|
* For internal use only. Use xSemaphoreTakeMutexRecursive() or
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -328,7 +328,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
||||||
* \defgroup xSemaphoreTake xSemaphoreTake
|
* \defgroup xSemaphoreTake xSemaphoreTake
|
||||||
* \ingroup Semaphores
|
* \ingroup Semaphores
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
|
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr. h
|
* semphr. h
|
||||||
|
@ -392,23 +392,23 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
||||||
|
|
||||||
// ...
|
// ...
|
||||||
// For some reason due to the nature of the code further calls to
|
// For some reason due to the nature of the code further calls to
|
||||||
// xSemaphoreTakeRecursive() are made on the same mutex. In real
|
// xSemaphoreTakeRecursive() are made on the same mutex. In real
|
||||||
// code these would not be just sequential calls as this would make
|
// code these would not be just sequential calls as this would make
|
||||||
// no sense. Instead the calls are likely to be buried inside
|
// no sense. Instead the calls are likely to be buried inside
|
||||||
// a more complex call structure.
|
// a more complex call structure.
|
||||||
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
|
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
|
||||||
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
|
xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 );
|
||||||
|
|
||||||
// The mutex has now been 'taken' three times, so will not be
|
// The mutex has now been 'taken' three times, so will not be
|
||||||
// available to another task until it has also been given back
|
// available to another task until it has also been given back
|
||||||
// three times. Again it is unlikely that real code would have
|
// three times. Again it is unlikely that real code would have
|
||||||
// these calls sequentially, but instead buried in a more complex
|
// these calls sequentially, but instead buried in a more complex
|
||||||
// call structure. This is just for illustrative purposes.
|
// call structure. This is just for illustrative purposes.
|
||||||
|
xSemaphoreGiveRecursive( xMutex );
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -1154,6 +1154,17 @@ typedef QueueHandle_t SemaphoreHandle_t;
|
||||||
*/
|
*/
|
||||||
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )
|
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* semphr.h
|
||||||
|
* <pre>TaskHandle_t xSemaphoreGetMutexHolderFromISR( SemaphoreHandle_t xMutex );</pre>
|
||||||
|
*
|
||||||
|
* If xMutex is indeed a mutex type semaphore, return the current mutex holder.
|
||||||
|
* If xMutex is not a mutex type semaphore, or the mutex is available (not held
|
||||||
|
* by a task), return NULL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define xSemaphoreGetMutexHolderFromISR( xSemaphore ) xQueueGetMutexHolderFromISR( ( xSemaphore ) )
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* semphr.h
|
* semphr.h
|
||||||
* <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre>
|
* <pre>UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );</pre>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -160,6 +160,9 @@ typedef struct xTASK_PARAMETERS
|
||||||
UBaseType_t uxPriority;
|
UBaseType_t uxPriority;
|
||||||
StackType_t *puxStackBuffer;
|
StackType_t *puxStackBuffer;
|
||||||
MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
|
MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ];
|
||||||
|
#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||||
|
StaticTask_t * const pxTaskBuffer;
|
||||||
|
#endif
|
||||||
} TaskParameters_t;
|
} TaskParameters_t;
|
||||||
|
|
||||||
/* Used with the uxTaskGetSystemState() function to return the state of each task
|
/* Used with the uxTaskGetSystemState() function to return the state of each task
|
||||||
|
@ -269,7 +272,7 @@ is used in assert() statements. */
|
||||||
BaseType_t xTaskCreate(
|
BaseType_t xTaskCreate(
|
||||||
TaskFunction_t pvTaskCode,
|
TaskFunction_t pvTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName,
|
||||||
uint16_t usStackDepth,
|
configSTACK_DEPTH_TYPE usStackDepth,
|
||||||
void *pvParameters,
|
void *pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
TaskHandle_t *pvCreatedTask
|
TaskHandle_t *pvCreatedTask
|
||||||
|
@ -358,11 +361,11 @@ is used in assert() statements. */
|
||||||
*/
|
*/
|
||||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const uint16_t usStackDepth,
|
const configSTACK_DEPTH_TYPE usStackDepth,
|
||||||
void * const pvParameters,
|
void * const pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -474,12 +477,12 @@ is used in assert() statements. */
|
||||||
*/
|
*/
|
||||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
|
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const uint32_t ulStackDepth,
|
const uint32_t ulStackDepth,
|
||||||
void * const pvParameters,
|
void * const pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
StackType_t * const puxStackBuffer,
|
StackType_t * const puxStackBuffer,
|
||||||
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;
|
||||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -487,6 +490,8 @@ is used in assert() statements. */
|
||||||
*<pre>
|
*<pre>
|
||||||
BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );</pre>
|
BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );</pre>
|
||||||
*
|
*
|
||||||
|
* Only available when configSUPPORT_DYNAMIC_ALLOCATION is set to 1.
|
||||||
|
*
|
||||||
* xTaskCreateRestricted() should only be used in systems that include an MPU
|
* xTaskCreateRestricted() should only be used in systems that include an MPU
|
||||||
* implementation.
|
* implementation.
|
||||||
*
|
*
|
||||||
|
@ -494,6 +499,9 @@ is used in assert() statements. */
|
||||||
* The function parameters define the memory regions and associated access
|
* The function parameters define the memory regions and associated access
|
||||||
* permissions allocated to the task.
|
* permissions allocated to the task.
|
||||||
*
|
*
|
||||||
|
* See xTaskCreateRestrictedStatic() for a version that does not use any
|
||||||
|
* dynamic memory allocation.
|
||||||
|
*
|
||||||
* @param pxTaskDefinition Pointer to a structure that contains a member
|
* @param pxTaskDefinition Pointer to a structure that contains a member
|
||||||
* for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
|
* for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
|
||||||
* documentation) plus an optional stack buffer and the memory region
|
* documentation) plus an optional stack buffer and the memory region
|
||||||
|
@ -553,6 +561,94 @@ TaskHandle_t xHandle;
|
||||||
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* task. h
|
||||||
|
*<pre>
|
||||||
|
BaseType_t xTaskCreateRestrictedStatic( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );</pre>
|
||||||
|
*
|
||||||
|
* Only available when configSUPPORT_STATIC_ALLOCATION is set to 1.
|
||||||
|
*
|
||||||
|
* xTaskCreateRestrictedStatic() should only be used in systems that include an
|
||||||
|
* MPU implementation.
|
||||||
|
*
|
||||||
|
* Internally, within the FreeRTOS implementation, tasks use two blocks of
|
||||||
|
* memory. The first block is used to hold the task's data structures. The
|
||||||
|
* second block is used by the task as its stack. If a task is created using
|
||||||
|
* xTaskCreateRestricted() then the stack is provided by the application writer,
|
||||||
|
* and the memory used to hold the task's data structure is automatically
|
||||||
|
* dynamically allocated inside the xTaskCreateRestricted() function. If a task
|
||||||
|
* is created using xTaskCreateRestrictedStatic() then the application writer
|
||||||
|
* must provide the memory used to hold the task's data structures too.
|
||||||
|
* xTaskCreateRestrictedStatic() therefore allows a memory protected task to be
|
||||||
|
* created without using any dynamic memory allocation.
|
||||||
|
*
|
||||||
|
* @param pxTaskDefinition Pointer to a structure that contains a member
|
||||||
|
* for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
|
||||||
|
* documentation) plus an optional stack buffer and the memory region
|
||||||
|
* definitions. If configSUPPORT_STATIC_ALLOCATION is set to 1 the structure
|
||||||
|
* contains an additional member, which is used to point to a variable of type
|
||||||
|
* StaticTask_t - which is then used to hold the task's data structure.
|
||||||
|
*
|
||||||
|
* @param pxCreatedTask Used to pass back a handle by which the created task
|
||||||
|
* can be referenced.
|
||||||
|
*
|
||||||
|
* @return pdPASS if the task was successfully created and added to a ready
|
||||||
|
* list, otherwise an error code defined in the file projdefs.h
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
<pre>
|
||||||
|
// Create an TaskParameters_t structure that defines the task to be created.
|
||||||
|
// The StaticTask_t variable is only included in the structure when
|
||||||
|
// configSUPPORT_STATIC_ALLOCATION is set to 1. The PRIVILEGED_DATA macro can
|
||||||
|
// be used to force the variable into the RTOS kernel's privileged data area.
|
||||||
|
static PRIVILEGED_DATA StaticTask_t xTaskBuffer;
|
||||||
|
static const TaskParameters_t xCheckTaskParameters =
|
||||||
|
{
|
||||||
|
vATask, // pvTaskCode - the function that implements the task.
|
||||||
|
"ATask", // pcName - just a text name for the task to assist debugging.
|
||||||
|
100, // usStackDepth - the stack size DEFINED IN WORDS.
|
||||||
|
NULL, // pvParameters - passed into the task function as the function parameters.
|
||||||
|
( 1UL | portPRIVILEGE_BIT ),// uxPriority - task priority, set the portPRIVILEGE_BIT if the task should run in a privileged state.
|
||||||
|
cStackBuffer,// puxStackBuffer - the buffer to be used as the task stack.
|
||||||
|
|
||||||
|
// xRegions - Allocate up to three separate memory regions for access by
|
||||||
|
// the task, with appropriate access permissions. Different processors have
|
||||||
|
// different memory alignment requirements - refer to the FreeRTOS documentation
|
||||||
|
// for full information.
|
||||||
|
{
|
||||||
|
// Base address Length Parameters
|
||||||
|
{ cReadWriteArray, 32, portMPU_REGION_READ_WRITE },
|
||||||
|
{ cReadOnlyArray, 32, portMPU_REGION_READ_ONLY },
|
||||||
|
{ cPrivilegedOnlyAccessArray, 128, portMPU_REGION_PRIVILEGED_READ_WRITE }
|
||||||
|
}
|
||||||
|
|
||||||
|
&xTaskBuffer; // Holds the task's data structure.
|
||||||
|
};
|
||||||
|
|
||||||
|
int main( void )
|
||||||
|
{
|
||||||
|
TaskHandle_t xHandle;
|
||||||
|
|
||||||
|
// Create a task from the const structure defined above. The task handle
|
||||||
|
// is requested (the second parameter is not NULL) but in this case just for
|
||||||
|
// demonstration purposes as its not actually used.
|
||||||
|
xTaskCreateRestricted( &xRegTest1Parameters, &xHandle );
|
||||||
|
|
||||||
|
// Start the scheduler.
|
||||||
|
vTaskStartScheduler();
|
||||||
|
|
||||||
|
// Will only get here if there was insufficient memory to create the idle
|
||||||
|
// and/or timer task.
|
||||||
|
for( ;; );
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
* \defgroup xTaskCreateRestrictedStatic xTaskCreateRestrictedStatic
|
||||||
|
* \ingroup Tasks
|
||||||
|
*/
|
||||||
|
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||||
|
BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* task. h
|
* task. h
|
||||||
*<pre>
|
*<pre>
|
||||||
|
@ -2141,14 +2237,14 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
|
||||||
* Removes a task from both the specified event list and the list of blocked
|
* Removes a task from both the specified event list and the list of blocked
|
||||||
* tasks, and places it on a ready queue.
|
* tasks, and places it on a ready queue.
|
||||||
*
|
*
|
||||||
* xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called
|
* xTaskRemoveFromEventList()/vTaskRemoveFromUnorderedEventList() will be called
|
||||||
* if either an event occurs to unblock a task, or the block timeout period
|
* if either an event occurs to unblock a task, or the block timeout period
|
||||||
* expires.
|
* expires.
|
||||||
*
|
*
|
||||||
* xTaskRemoveFromEventList() is used when the event list is in task priority
|
* xTaskRemoveFromEventList() is used when the event list is in task priority
|
||||||
* order. It removes the list item from the head of the event list as that will
|
* order. It removes the list item from the head of the event list as that will
|
||||||
* have the highest priority owning task of all the tasks on the event list.
|
* have the highest priority owning task of all the tasks on the event list.
|
||||||
* xTaskRemoveFromUnorderedEventList() is used when the event list is not
|
* vTaskRemoveFromUnorderedEventList() is used when the event list is not
|
||||||
* ordered and the event list items hold something other than the owning tasks
|
* ordered and the event list items hold something other than the owning tasks
|
||||||
* priority. In this case the event list item value is updated to the value
|
* priority. In this case the event list item value is updated to the value
|
||||||
* passed in the xItemValue parameter.
|
* passed in the xItemValue parameter.
|
||||||
|
@ -2157,7 +2253,7 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
|
||||||
* making the call, otherwise pdFALSE.
|
* making the call, otherwise pdFALSE.
|
||||||
*/
|
*/
|
||||||
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
|
||||||
BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
|
void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
|
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
|
||||||
|
@ -2207,7 +2303,7 @@ BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
|
||||||
* Raises the priority of the mutex holder to that of the calling task should
|
* Raises the priority of the mutex holder to that of the calling task should
|
||||||
* the mutex holder have a priority less than the calling task.
|
* the mutex holder have a priority less than the calling task.
|
||||||
*/
|
*/
|
||||||
void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the priority of a task back to its proper priority in the case that it
|
* Set the priority of a task back to its proper priority in the case that it
|
||||||
|
@ -2215,6 +2311,16 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO
|
||||||
*/
|
*/
|
||||||
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a higher priority task attempting to obtain a mutex caused a lower
|
||||||
|
* priority task to inherit the higher priority task's priority - but the higher
|
||||||
|
* priority task then timed out without obtaining the mutex, then the lower
|
||||||
|
* priority task will disinherit the priority again - but only down as far as
|
||||||
|
* the highest priority task that is still waiting for the mutex (if there were
|
||||||
|
* more than one task waiting for the mutex).
|
||||||
|
*/
|
||||||
|
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
|
* Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
|
||||||
*/
|
*/
|
||||||
|
@ -2258,6 +2364,13 @@ eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION;
|
||||||
*/
|
*/
|
||||||
void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;
|
void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For internal use only. Same as vTaskSetTimeOutState(), but without a critial
|
||||||
|
* section.
|
||||||
|
*/
|
||||||
|
void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -75,10 +75,10 @@
|
||||||
#error "include FreeRTOS.h must appear in source files before include timers.h"
|
#error "include FreeRTOS.h must appear in source files before include timers.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*lint -e537 This headers are only multiply included if the application code
|
/*lint -save -e537 This headers are only multiply included if the application code
|
||||||
happens to also be including task.h. */
|
happens to also be including task.h. */
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
/*lint +e537 */
|
/*lint -restore */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -266,11 +266,11 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const TickType_t xTimerPeriodInTicks,
|
const TickType_t xTimerPeriodInTicks,
|
||||||
const UBaseType_t uxAutoReload,
|
const UBaseType_t uxAutoReload,
|
||||||
void * const pvTimerID,
|
void * const pvTimerID,
|
||||||
TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -396,12 +396,12 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,
|
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const TickType_t xTimerPeriodInTicks,
|
const TickType_t xTimerPeriodInTicks,
|
||||||
const UBaseType_t uxAutoReload,
|
const UBaseType_t uxAutoReload,
|
||||||
void * const pvTimerID,
|
void * const pvTimerID,
|
||||||
TimerCallbackFunction_t pxCallbackFunction,
|
TimerCallbackFunction_t pxCallbackFunction,
|
||||||
StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION;
|
||||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
||||||
|
@ -73,10 +73,12 @@
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <xtensa_ops.h>
|
#include <xtensa_ops.h>
|
||||||
|
|
||||||
#include "FreeRTOS.h"
|
#include "FreeRTOS.h"
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
#include "queue.h"
|
||||||
#include "xtensa_rtos.h"
|
#include "xtensa_rtos.h"
|
||||||
|
|
||||||
unsigned cpu_sr;
|
unsigned cpu_sr;
|
||||||
|
@ -91,6 +93,13 @@ char level1_int_disabled;
|
||||||
*/
|
*/
|
||||||
void *xPortSupervisorStackPointer;
|
void *xPortSupervisorStackPointer;
|
||||||
|
|
||||||
|
void vAssertCalled(const char * pcFile, unsigned long ulLine)
|
||||||
|
{
|
||||||
|
printf("rtos assert %s %lu\n", pcFile, ulLine);
|
||||||
|
abort();
|
||||||
|
//for (;;);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stack initialization
|
* Stack initialization
|
||||||
*/
|
*/
|
||||||
|
@ -100,7 +109,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
|
||||||
portSTACK_TYPE *sp, *tp;
|
portSTACK_TYPE *sp, *tp;
|
||||||
|
|
||||||
/* Create interrupt stack frame aligned to 16 byte boundary */
|
/* Create interrupt stack frame aligned to 16 byte boundary */
|
||||||
sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack+1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf);
|
sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack + 1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf);
|
||||||
|
|
||||||
/* Clear the entire frame (do not use memset() because we don't depend on C library) */
|
/* Clear the entire frame (do not use memset() because we don't depend on C library) */
|
||||||
for (tp = sp; tp <= pxTopOfStack; ++tp)
|
for (tp = sp; tp <= pxTopOfStack; ++tp)
|
||||||
|
@ -121,30 +130,29 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
|
||||||
static int pending_soft_sv;
|
static int pending_soft_sv;
|
||||||
static int pending_maclayer_sv;
|
static int pending_maclayer_sv;
|
||||||
|
|
||||||
/* PendSV is called in place of vPortYield() to request a supervisor
|
/*
|
||||||
call.
|
* The portYIELD macro calls PendSV with SVC_Software to set a pending interrupt
|
||||||
|
* service callback that allows a task switch, and this occur when interrupts
|
||||||
The portYIELD macro calls pendSV if it's a software request.
|
* are enabled which might be after exiting the critical region below.
|
||||||
|
*
|
||||||
The libpp and libudhcp libraries also call this function, assuming
|
* The wdev NMI calls this function from pp_post() with SVC_MACLayer to set a
|
||||||
always with arg==2 (but maybe sometimes with arg==1?)
|
* pending interrupt service callback which flushs the queue of messages that
|
||||||
|
* the NMI stashes away. This interrupt will be triggered after the return from
|
||||||
In the original esp_iot_rtos_sdk implementation, arg was a char. Using an
|
* the NMI and when interrupts are enabled. The NMI can not touch the FreeRTOS
|
||||||
enum is ABI-compatible, though.
|
* queues itself. The NMI must not touch the interrupt masks so that path must
|
||||||
*/
|
* not call vPortEnterCritical and vPortExitCritical.
|
||||||
|
*/
|
||||||
void IRAM PendSV(enum SVC_ReqType req)
|
void IRAM PendSV(enum SVC_ReqType req)
|
||||||
{
|
{
|
||||||
vPortEnterCritical();
|
if (req == SVC_Software) {
|
||||||
|
vPortEnterCritical();
|
||||||
if(req == SVC_Software)
|
pending_soft_sv = 1;
|
||||||
{
|
WSR(BIT(INUM_SOFT), interrupt);
|
||||||
pending_soft_sv = 1;
|
vPortExitCritical();
|
||||||
}
|
} else if (req == SVC_MACLayer) {
|
||||||
else if(req == SVC_MACLayer)
|
pending_maclayer_sv= 1;
|
||||||
pending_maclayer_sv= 1;
|
WSR(BIT(INUM_SOFT), interrupt);
|
||||||
|
}
|
||||||
WSR(BIT(INUM_SOFT), interrupt);
|
|
||||||
vPortExitCritical();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This MAC layer ISR handler is defined in libpp.a, and is called
|
/* This MAC layer ISR handler is defined in libpp.a, and is called
|
||||||
|
@ -153,31 +161,24 @@ void IRAM PendSV(enum SVC_ReqType req)
|
||||||
*/
|
*/
|
||||||
extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void);
|
extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void);
|
||||||
|
|
||||||
void IRAM SV_ISR(void)
|
void IRAM SV_ISR(void *arg)
|
||||||
{
|
{
|
||||||
portBASE_TYPE xHigherPriorityTaskWoken=pdFALSE ;
|
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE ;
|
||||||
if(pending_maclayer_sv)
|
if (pending_maclayer_sv) {
|
||||||
{
|
xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
|
||||||
xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
|
pending_maclayer_sv = 0;
|
||||||
pending_maclayer_sv = 0;
|
}
|
||||||
}
|
if (xHigherPriorityTaskWoken || pending_soft_sv) {
|
||||||
if( xHigherPriorityTaskWoken || pending_soft_sv)
|
sdk__xt_timer_int1();
|
||||||
{
|
pending_soft_sv = 0;
|
||||||
sdk__xt_timer_int1();
|
}
|
||||||
pending_soft_sv = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void xPortSysTickHandle (void)
|
void xPortSysTickHandle (void)
|
||||||
{
|
{
|
||||||
//CloseNMI();
|
if (xTaskIncrementTick() != pdFALSE) {
|
||||||
{
|
vTaskSwitchContext();
|
||||||
if(xTaskIncrementTick() !=pdFALSE )
|
}
|
||||||
{
|
|
||||||
vTaskSwitchContext();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//OpenNMI();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -185,11 +186,11 @@ void xPortSysTickHandle (void)
|
||||||
*/
|
*/
|
||||||
portBASE_TYPE xPortStartScheduler( void )
|
portBASE_TYPE xPortStartScheduler( void )
|
||||||
{
|
{
|
||||||
_xt_isr_attach(INUM_SOFT, SV_ISR);
|
_xt_isr_attach(INUM_SOFT, SV_ISR, NULL);
|
||||||
_xt_isr_unmask(BIT(INUM_SOFT));
|
_xt_isr_unmask(BIT(INUM_SOFT));
|
||||||
|
|
||||||
/* Initialize system tick timer interrupt and schedule the first tick. */
|
/* Initialize system tick timer interrupt and schedule the first tick. */
|
||||||
_xt_isr_attach(INUM_TICK, sdk__xt_timer_int);
|
_xt_isr_attach(INUM_TICK, sdk__xt_timer_int, NULL);
|
||||||
_xt_isr_unmask(BIT(INUM_TICK));
|
_xt_isr_unmask(BIT(INUM_TICK));
|
||||||
sdk__xt_tick_timer_init();
|
sdk__xt_tick_timer_init();
|
||||||
|
|
||||||
|
@ -221,8 +222,10 @@ size_t xPortGetFreeHeapSize( void )
|
||||||
uint32_t brk_val = (uint32_t) sbrk(0);
|
uint32_t brk_val = (uint32_t) sbrk(0);
|
||||||
|
|
||||||
intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
|
intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
|
||||||
if(sp == 0) /* scheduler not started */
|
if (sp == 0) {
|
||||||
|
/* scheduler not started */
|
||||||
SP(sp);
|
SP(sp);
|
||||||
|
}
|
||||||
return sp - brk_val + mi.fordblks;
|
return sp - brk_val + mi.fordblks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,8 +236,6 @@ void vPortEndScheduler( void )
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* Each task maintains its own interrupt status in the critical nesting
|
|
||||||
variable. */
|
|
||||||
static unsigned portBASE_TYPE uxCriticalNesting = 0;
|
static unsigned portBASE_TYPE uxCriticalNesting = 0;
|
||||||
|
|
||||||
/* These nested vPortEnter/ExitCritical macros are called by SDK
|
/* These nested vPortEnter/ExitCritical macros are called by SDK
|
||||||
|
@ -243,26 +244,42 @@ static unsigned portBASE_TYPE uxCriticalNesting = 0;
|
||||||
* It may be possible to replace the global nesting count variable
|
* It may be possible to replace the global nesting count variable
|
||||||
* with a save/restore of interrupt level, although it's difficult as
|
* with a save/restore of interrupt level, although it's difficult as
|
||||||
* the functions have no return value.
|
* the functions have no return value.
|
||||||
|
*
|
||||||
|
* These should not be called from the NMI in regular operation and
|
||||||
|
* the NMI must not touch the interrupt mask, but that might occur in
|
||||||
|
* exceptional paths such as aborts and debug code.
|
||||||
*/
|
*/
|
||||||
void IRAM vPortEnterCritical( void )
|
void IRAM vPortEnterCritical(void) {
|
||||||
{
|
|
||||||
portDISABLE_INTERRUPTS();
|
portDISABLE_INTERRUPTS();
|
||||||
uxCriticalNesting++;
|
uxCriticalNesting++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void IRAM vPortExitCritical( void )
|
void IRAM vPortExitCritical(void) {
|
||||||
{
|
|
||||||
uxCriticalNesting--;
|
uxCriticalNesting--;
|
||||||
if( uxCriticalNesting == 0 )
|
if (uxCriticalNesting == 0)
|
||||||
portENABLE_INTERRUPTS();
|
portENABLE_INTERRUPTS();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Backward compatibility with libmain.a and libpp.a and can remove when these are open. */
|
/* Backward compatibility, for the sdk library. */
|
||||||
signed portBASE_TYPE xTaskGenericCreate( TaskFunction_t pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, TaskHandle_t *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const MemoryRegion_t * const xRegions )
|
|
||||||
{
|
signed portBASE_TYPE xTaskGenericCreate(TaskFunction_t pxTaskCode,
|
||||||
(void)puxStackBuffer; (void)xRegions;
|
const signed char * const pcName,
|
||||||
return xTaskCreate( pxTaskCode, (const char * const)pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
|
unsigned short usStackDepth,
|
||||||
|
void *pvParameters,
|
||||||
|
unsigned portBASE_TYPE uxPriority,
|
||||||
|
TaskHandle_t *pxCreatedTask,
|
||||||
|
portSTACK_TYPE *puxStackBuffer,
|
||||||
|
const MemoryRegion_t * const xRegions) {
|
||||||
|
(void)puxStackBuffer;
|
||||||
|
(void)xRegions;
|
||||||
|
return xTaskCreate(pxTaskCode, (const char * const)pcName, usStackDepth,
|
||||||
|
pvParameters, uxPriority, pxCreatedTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BaseType_t xQueueGenericReceive(QueueHandle_t xQueue, void * const pvBuffer,
|
||||||
|
TickType_t xTicksToWait, const BaseType_t xJustPeeking) {
|
||||||
|
configASSERT(xJustPeeking == 0);
|
||||||
|
return xQueueReceive(xQueue, pvBuffer, xTicksToWait);
|
||||||
|
}
|
||||||
|
|
|
@ -1,65 +1,29 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* FreeRTOS provides completely free yet professionally developed, *
|
|
||||||
* robust, strictly quality controlled, supported, and cross *
|
|
||||||
* platform software that has become a de facto standard. *
|
|
||||||
* *
|
|
||||||
* Help yourself get started quickly and support the FreeRTOS *
|
|
||||||
* project by purchasing a FreeRTOS tutorial book, reference *
|
|
||||||
* manual, or both from: http://www.FreeRTOS.org/Documentation *
|
|
||||||
* *
|
|
||||||
* Thank you! *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
|
|
||||||
This file is part of the FreeRTOS distribution.
|
This file is part of the FreeRTOS distribution.
|
||||||
|
|
||||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||||
the terms of the GNU General Public License (version 2) as published by the
|
the terms of the GNU General Public License (version 2) as published by the
|
||||||
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
|
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
|
||||||
|
|
||||||
>>! NOTE: The modification to the GPL is included to allow you to distribute
|
***************************************************************************
|
||||||
>>! a combined work that includes FreeRTOS without being obliged to provide
|
>>! NOTE: The modification to the GPL is included to allow you to !<<
|
||||||
>>! the source code for proprietary components outside of the FreeRTOS
|
>>! distribute a combined work that includes FreeRTOS without being !<<
|
||||||
>>! kernel.
|
>>! obliged to provide the source code for proprietary components !<<
|
||||||
|
>>! outside of the FreeRTOS kernel. !<<
|
||||||
|
***************************************************************************
|
||||||
|
|
||||||
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
FOR A PARTICULAR PURPOSE. Full license text is available from the following
|
FOR A PARTICULAR PURPOSE. Full license text is available on the following
|
||||||
link: http://www.freertos.org/a00114.html
|
link: http://www.freertos.org/a00114.html
|
||||||
|
|
||||||
1 tab == 4 spaces!
|
1 tab == 4 spaces!
|
||||||
|
|
||||||
***************************************************************************
|
|
||||||
* *
|
|
||||||
* Having a problem? Start by reading the FAQ "My application does *
|
|
||||||
* not run, what could be wrong?" *
|
|
||||||
* *
|
|
||||||
* http://www.FreeRTOS.org/FAQHelp.html *
|
|
||||||
* *
|
|
||||||
***************************************************************************
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
|
|
||||||
license and Real Time Engineers Ltd. contact details.
|
|
||||||
|
|
||||||
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
|
|
||||||
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
|
|
||||||
compatible FAT file system, and our tiny thread aware UDP/IP stack.
|
|
||||||
|
|
||||||
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
|
|
||||||
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
|
|
||||||
licenses offer ticketed support, indemnification and middleware.
|
|
||||||
|
|
||||||
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
|
|
||||||
engineered and independently SIL3 certified version for use in safety and
|
|
||||||
mission critical applications that require provable dependability.
|
|
||||||
|
|
||||||
1 tab == 4 spaces!
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -92,16 +56,15 @@ extern "C" {
|
||||||
#define portDOUBLE double
|
#define portDOUBLE double
|
||||||
#define portLONG long
|
#define portLONG long
|
||||||
#define portSHORT short
|
#define portSHORT short
|
||||||
#define portSTACK_TYPE unsigned portLONG
|
#define portSTACK_TYPE uint32_t
|
||||||
#define portBASE_TYPE long
|
#define portBASE_TYPE long
|
||||||
#define portPOINTER_SIZE_TYPE unsigned portLONG
|
|
||||||
|
|
||||||
typedef portSTACK_TYPE StackType_t;
|
typedef portSTACK_TYPE StackType_t;
|
||||||
typedef portBASE_TYPE BaseType_t;
|
typedef portBASE_TYPE BaseType_t;
|
||||||
typedef unsigned portBASE_TYPE UBaseType_t;
|
typedef unsigned portBASE_TYPE UBaseType_t;
|
||||||
|
|
||||||
typedef uint32_t TickType_t;
|
typedef uint32_t TickType_t;
|
||||||
#define portMAX_DELAY ( TickType_t ) 0xffffffff
|
#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
|
||||||
|
|
||||||
/* Architecture specifics. */
|
/* Architecture specifics. */
|
||||||
#define portSTACK_GROWTH ( -1 )
|
#define portSTACK_GROWTH ( -1 )
|
||||||
|
@ -156,6 +119,9 @@ extern unsigned cpu_sr;
|
||||||
prefer to _xt_disable_interrupts & _xt_enable_interrupts and store
|
prefer to _xt_disable_interrupts & _xt_enable_interrupts and store
|
||||||
the ps value in a local variable - that approach is recursive-safe
|
the ps value in a local variable - that approach is recursive-safe
|
||||||
and generally better.
|
and generally better.
|
||||||
|
|
||||||
|
The NMI must not touch the interrupt mask and it should not in
|
||||||
|
regular operation, but there is a guard here just in case.
|
||||||
*/
|
*/
|
||||||
inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void)
|
inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void)
|
||||||
{
|
{
|
||||||
|
@ -185,6 +151,10 @@ not necessary for to use this port. They are defined so the common demo files
|
||||||
(which build with all the ports) will build. */
|
(which build with all the ports) will build. */
|
||||||
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
|
||||||
|
|
||||||
|
/* FreeRTOS API functions should not be called from the NMI handler. */
|
||||||
|
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT(sdk_NMIIrqIsOn == 0)
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
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
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -255,6 +255,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
|
||||||
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
|
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
/*
|
||||||
|
* If a task waiting for a mutex causes the mutex holder to inherit a
|
||||||
|
* priority, but the waiting task times out, then the holder should
|
||||||
|
* disinherit the priority - but only down to the highest priority of any
|
||||||
|
* other tasks that are waiting for the same mutex. This function returns
|
||||||
|
* that priority.
|
||||||
|
*/
|
||||||
|
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
|
||||||
|
#endif
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -374,6 +384,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
|
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
traceQUEUE_CREATE_FAILED( ucQueueType );
|
||||||
|
}
|
||||||
|
|
||||||
return pxNewQueue;
|
return pxNewQueue;
|
||||||
}
|
}
|
||||||
|
@ -422,6 +436,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
|
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
traceQUEUE_CREATE_FAILED( ucQueueType );
|
||||||
|
}
|
||||||
|
|
||||||
return pxNewQueue;
|
return pxNewQueue;
|
||||||
}
|
}
|
||||||
|
@ -567,6 +585,32 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
|
||||||
#endif
|
#endif
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) )
|
||||||
|
|
||||||
|
void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore )
|
||||||
|
{
|
||||||
|
void *pxReturn;
|
||||||
|
|
||||||
|
configASSERT( xSemaphore );
|
||||||
|
|
||||||
|
/* Mutexes cannot be used in interrupt service routines, so the mutex
|
||||||
|
holder should not change in an ISR, and therefore a critical section is
|
||||||
|
not required here. */
|
||||||
|
if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX )
|
||||||
|
{
|
||||||
|
pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pxReturn = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pxReturn;
|
||||||
|
} /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( configUSE_RECURSIVE_MUTEXES == 1 )
|
#if ( configUSE_RECURSIVE_MUTEXES == 1 )
|
||||||
|
|
||||||
BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
|
BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
|
||||||
|
@ -643,7 +687,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE );
|
xReturn = xQueueSemaphoreTake( pxMutex, xTicksToWait );
|
||||||
|
|
||||||
/* pdPASS will only be returned if the mutex was successfully
|
/* pdPASS will only be returned if the mutex was successfully
|
||||||
obtained. The calling task may have entered the Blocked state
|
obtained. The calling task may have entered the Blocked state
|
||||||
|
@ -855,7 +899,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
{
|
{
|
||||||
/* The queue was full and a block time was specified so
|
/* The queue was full and a block time was specified so
|
||||||
configure the timeout structure. */
|
configure the timeout structure. */
|
||||||
vTaskSetTimeOutState( &xTimeOut );
|
vTaskInternalSetTimeOutState( &xTimeOut );
|
||||||
xEntryTimeSet = pdTRUE;
|
xEntryTimeSet = pdTRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1127,7 +1171,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
can be assumed there is no mutex holder and no need to determine if
|
can be assumed there is no mutex holder and no need to determine if
|
||||||
priority disinheritance is needed. Simply increase the count of
|
priority disinheritance is needed. Simply increase the count of
|
||||||
messages (semaphores) available. */
|
messages (semaphores) available. */
|
||||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;
|
pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
|
||||||
|
|
||||||
/* The event list is not altered if the queue is locked. This will
|
/* The event list is not altered if the queue is locked. This will
|
||||||
be done when the queue is unlocked later. */
|
be done when the queue is unlocked later. */
|
||||||
|
@ -1234,21 +1278,27 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
|
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
|
||||||
{
|
{
|
||||||
BaseType_t xEntryTimeSet = pdFALSE;
|
BaseType_t xEntryTimeSet = pdFALSE;
|
||||||
TimeOut_t xTimeOut;
|
TimeOut_t xTimeOut;
|
||||||
int8_t *pcOriginalReadPosition;
|
|
||||||
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
configASSERT( pxQueue );
|
/* Check the pointer is not NULL. */
|
||||||
configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
|
configASSERT( ( pxQueue ) );
|
||||||
|
|
||||||
|
/* The buffer into which data is received can only be NULL if the data size
|
||||||
|
is zero (so no data is copied into the buffer. */
|
||||||
|
configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
|
||||||
|
|
||||||
|
/* Cannot block if the scheduler is suspended. */
|
||||||
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||||
{
|
{
|
||||||
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* This function relaxes the coding standard somewhat to allow return
|
/* This function relaxes the coding standard somewhat to allow return
|
||||||
statements within the function itself. This is done in the interest
|
statements within the function itself. This is done in the interest
|
||||||
of execution time efficiency. */
|
of execution time efficiency. */
|
||||||
|
@ -1263,44 +1313,19 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
must be the highest priority task wanting to access the queue. */
|
must be the highest priority task wanting to access the queue. */
|
||||||
if( uxMessagesWaiting > ( UBaseType_t ) 0 )
|
if( uxMessagesWaiting > ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
/* Remember the read position in case the queue is only being
|
/* Data available, remove one item. */
|
||||||
peeked. */
|
|
||||||
pcOriginalReadPosition = pxQueue->u.pcReadFrom;
|
|
||||||
|
|
||||||
prvCopyDataFromQueue( pxQueue, pvBuffer );
|
prvCopyDataFromQueue( pxQueue, pvBuffer );
|
||||||
|
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 );
|
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
|
||||||
|
|
||||||
/* Actually removing data, not just peeking. */
|
|
||||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
|
|
||||||
|
|
||||||
#if ( configUSE_MUTEXES == 1 )
|
|
||||||
{
|
{
|
||||||
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
|
queueYIELD_IF_USING_PREEMPTION();
|
||||||
{
|
|
||||||
/* 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1309,30 +1334,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
traceQUEUE_PEEK( pxQueue );
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
|
||||||
/* The data is not being removed, so reset the read
|
|
||||||
pointer. */
|
|
||||||
pxQueue->u.pcReadFrom = pcOriginalReadPosition;
|
|
||||||
|
|
||||||
/* The data is being left in the queue, so see if there are
|
|
||||||
any other tasks waiting for the data. */
|
|
||||||
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
|
|
||||||
{
|
|
||||||
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
|
|
||||||
{
|
|
||||||
/* The task waiting has a higher priority than this task. */
|
|
||||||
queueYIELD_IF_USING_PREEMPTION();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mtCOVERAGE_TEST_MARKER();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mtCOVERAGE_TEST_MARKER();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
@ -1352,7 +1354,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
{
|
{
|
||||||
/* The queue was empty and a block time was specified so
|
/* The queue was empty and a block time was specified so
|
||||||
configure the timeout structure. */
|
configure the timeout structure. */
|
||||||
vTaskSetTimeOutState( &xTimeOut );
|
vTaskInternalSetTimeOutState( &xTimeOut );
|
||||||
xEntryTimeSet = pdTRUE;
|
xEntryTimeSet = pdTRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1373,6 +1375,182 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
/* Update the timeout state to see if it has expired yet. */
|
/* Update the timeout state to see if it has expired yet. */
|
||||||
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
|
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
|
||||||
{
|
{
|
||||||
|
/* The timeout has not expired. If the queue is still empty place
|
||||||
|
the task on the list of tasks waiting to receive from the queue. */
|
||||||
|
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
||||||
|
{
|
||||||
|
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
|
||||||
|
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
||||||
|
prvUnlockQueue( pxQueue );
|
||||||
|
if( xTaskResumeAll() == pdFALSE )
|
||||||
|
{
|
||||||
|
portYIELD_WITHIN_API();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The queue contains data again. Loop back to try and read the
|
||||||
|
data. */
|
||||||
|
prvUnlockQueue( pxQueue );
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Timed out. If there is no data in the queue exit, otherwise loop
|
||||||
|
back and attempt to read the data. */
|
||||||
|
prvUnlockQueue( pxQueue );
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
|
||||||
|
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
||||||
|
{
|
||||||
|
traceQUEUE_RECEIVE_FAILED( pxQueue );
|
||||||
|
return errQUEUE_EMPTY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
|
||||||
|
{
|
||||||
|
BaseType_t xEntryTimeSet = pdFALSE;
|
||||||
|
TimeOut_t xTimeOut;
|
||||||
|
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
BaseType_t xInheritanceOccurred = pdFALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check the queue pointer is not NULL. */
|
||||||
|
configASSERT( ( pxQueue ) );
|
||||||
|
|
||||||
|
/* Check this really is a semaphore, in which case the item size will be
|
||||||
|
0. */
|
||||||
|
configASSERT( pxQueue->uxItemSize == 0 );
|
||||||
|
|
||||||
|
/* Cannot block if the scheduler is suspended. */
|
||||||
|
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||||
|
{
|
||||||
|
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* This function relaxes the coding standard somewhat to allow return
|
||||||
|
statements within the function itself. This is done in the interest
|
||||||
|
of execution time efficiency. */
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
/* Semaphores are queues with an item size of 0, and where the
|
||||||
|
number of messages in the queue is the semaphore's count value. */
|
||||||
|
const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;
|
||||||
|
|
||||||
|
/* Is there data in the queue now? To be running the calling task
|
||||||
|
must be the highest priority task wanting to access the queue. */
|
||||||
|
if( uxSemaphoreCount > ( UBaseType_t ) 0 )
|
||||||
|
{
|
||||||
|
traceQUEUE_RECEIVE( pxQueue );
|
||||||
|
|
||||||
|
/* Semaphores are queues with a data size of zero and where the
|
||||||
|
messages waiting is the semaphore's count. Reduce the count. */
|
||||||
|
pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;
|
||||||
|
|
||||||
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
|
{
|
||||||
|
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
|
||||||
|
{
|
||||||
|
/* Record the information required to implement
|
||||||
|
priority inheritance should it become necessary. */
|
||||||
|
pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
|
||||||
|
/* Check to see if other tasks are blocked waiting to give the
|
||||||
|
semaphore, and if so, unblock the highest priority such task. */
|
||||||
|
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
|
||||||
|
{
|
||||||
|
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
|
||||||
|
{
|
||||||
|
queueYIELD_IF_USING_PREEMPTION();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
return pdPASS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( xTicksToWait == ( TickType_t ) 0 )
|
||||||
|
{
|
||||||
|
/* For inheritance to have occurred there must have been an
|
||||||
|
initial timeout, and an adjusted timeout cannot become 0, as
|
||||||
|
if it were 0 the function would have exited. */
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
{
|
||||||
|
configASSERT( xInheritanceOccurred == pdFALSE );
|
||||||
|
}
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
|
||||||
|
/* The semaphore count was 0 and no block time is specified
|
||||||
|
(or the block time has expired) so exit now. */
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
traceQUEUE_RECEIVE_FAILED( pxQueue );
|
||||||
|
return errQUEUE_EMPTY;
|
||||||
|
}
|
||||||
|
else if( xEntryTimeSet == pdFALSE )
|
||||||
|
{
|
||||||
|
/* The semaphore count was 0 and a block time was specified
|
||||||
|
so configure the timeout structure ready to block. */
|
||||||
|
vTaskInternalSetTimeOutState( &xTimeOut );
|
||||||
|
xEntryTimeSet = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Entry time was already set. */
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
/* Interrupts and other tasks can give to and take from the semaphore
|
||||||
|
now the critical section has been exited. */
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
prvLockQueue( pxQueue );
|
||||||
|
|
||||||
|
/* Update the timeout state to see if it has expired yet. */
|
||||||
|
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
|
||||||
|
{
|
||||||
|
/* A block time is specified and not expired. If the semaphore
|
||||||
|
count is 0 then enter the Blocked state to wait for a semaphore to
|
||||||
|
become available. As semaphores are implemented with queues the
|
||||||
|
queue being empty is equivalent to the semaphore count being 0. */
|
||||||
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
||||||
{
|
{
|
||||||
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
|
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
|
||||||
|
@ -1383,7 +1561,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
{
|
{
|
||||||
taskENTER_CRITICAL();
|
taskENTER_CRITICAL();
|
||||||
{
|
{
|
||||||
vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
|
xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
}
|
}
|
||||||
|
@ -1407,13 +1585,193 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Try again. */
|
/* There was no timeout and the semaphore count was not 0, so
|
||||||
|
attempt to take the semaphore again. */
|
||||||
prvUnlockQueue( pxQueue );
|
prvUnlockQueue( pxQueue );
|
||||||
( void ) xTaskResumeAll();
|
( void ) xTaskResumeAll();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Timed out. */
|
||||||
|
prvUnlockQueue( pxQueue );
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
|
||||||
|
/* If the semaphore count is 0 exit now as the timeout has
|
||||||
|
expired. Otherwise return to attempt to take the semaphore that is
|
||||||
|
known to be available. As semaphores are implemented by queues the
|
||||||
|
queue being empty is equivalent to the semaphore count being 0. */
|
||||||
|
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
||||||
|
{
|
||||||
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
|
{
|
||||||
|
/* xInheritanceOccurred could only have be set if
|
||||||
|
pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to
|
||||||
|
test the mutex type again to check it is actually a mutex. */
|
||||||
|
if( xInheritanceOccurred != pdFALSE )
|
||||||
|
{
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
UBaseType_t uxHighestWaitingPriority;
|
||||||
|
|
||||||
|
/* This task blocking on the mutex caused another
|
||||||
|
task to inherit this task's priority. Now this task
|
||||||
|
has timed out the priority should be disinherited
|
||||||
|
again, but only as low as the next highest priority
|
||||||
|
task that is waiting for the same mutex. */
|
||||||
|
uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );
|
||||||
|
vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
|
||||||
|
traceQUEUE_RECEIVE_FAILED( pxQueue );
|
||||||
|
return errQUEUE_EMPTY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
|
||||||
|
{
|
||||||
|
BaseType_t xEntryTimeSet = pdFALSE;
|
||||||
|
TimeOut_t xTimeOut;
|
||||||
|
int8_t *pcOriginalReadPosition;
|
||||||
|
Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
|
|
||||||
|
/* Check the pointer is not NULL. */
|
||||||
|
configASSERT( ( pxQueue ) );
|
||||||
|
|
||||||
|
/* The buffer into which data is received can only be NULL if the data size
|
||||||
|
is zero (so no data is copied into the buffer. */
|
||||||
|
configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
|
||||||
|
|
||||||
|
/* Cannot block if the scheduler is suspended. */
|
||||||
|
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
|
||||||
|
{
|
||||||
|
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* This function relaxes the coding standard somewhat to allow return
|
||||||
|
statements within the function itself. This is done in the interest
|
||||||
|
of execution time efficiency. */
|
||||||
|
|
||||||
|
for( ;; )
|
||||||
|
{
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
|
||||||
|
|
||||||
|
/* Is there data in the queue now? To be running the calling task
|
||||||
|
must be the highest priority task wanting to access the queue. */
|
||||||
|
if( uxMessagesWaiting > ( UBaseType_t ) 0 )
|
||||||
|
{
|
||||||
|
/* Remember the read position so it can be reset after the data
|
||||||
|
is read from the queue as this function is only peeking the
|
||||||
|
data, not removing it. */
|
||||||
|
pcOriginalReadPosition = pxQueue->u.pcReadFrom;
|
||||||
|
|
||||||
|
prvCopyDataFromQueue( pxQueue, pvBuffer );
|
||||||
|
traceQUEUE_PEEK( pxQueue );
|
||||||
|
|
||||||
|
/* The data is not being removed, so reset the read pointer. */
|
||||||
|
pxQueue->u.pcReadFrom = pcOriginalReadPosition;
|
||||||
|
|
||||||
|
/* The data is being left in the queue, so see if there are
|
||||||
|
any other tasks waiting for the data. */
|
||||||
|
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
|
||||||
|
{
|
||||||
|
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
|
||||||
|
{
|
||||||
|
/* The task waiting has a higher priority than this task. */
|
||||||
|
queueYIELD_IF_USING_PREEMPTION();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
return pdPASS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( xTicksToWait == ( TickType_t ) 0 )
|
||||||
|
{
|
||||||
|
/* The queue was empty and no block time is specified (or
|
||||||
|
the block time has expired) so leave now. */
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
traceQUEUE_RECEIVE_FAILED( pxQueue );
|
||||||
|
return errQUEUE_EMPTY;
|
||||||
|
}
|
||||||
|
else if( xEntryTimeSet == pdFALSE )
|
||||||
|
{
|
||||||
|
/* The queue was empty and a block time was specified so
|
||||||
|
configure the timeout structure ready to enter the blocked
|
||||||
|
state. */
|
||||||
|
vTaskInternalSetTimeOutState( &xTimeOut );
|
||||||
|
xEntryTimeSet = pdTRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Entry time was already set. */
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
/* Interrupts and other tasks can send to and receive from the queue
|
||||||
|
now the critical section has been exited. */
|
||||||
|
|
||||||
|
vTaskSuspendAll();
|
||||||
|
prvLockQueue( pxQueue );
|
||||||
|
|
||||||
|
/* Update the timeout state to see if it has expired yet. */
|
||||||
|
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
|
||||||
|
{
|
||||||
|
/* Timeout has not expired yet, check to see if there is data in the
|
||||||
|
queue now, and if not enter the Blocked state to wait for data. */
|
||||||
|
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
|
||||||
|
{
|
||||||
|
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
|
||||||
|
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
|
||||||
|
prvUnlockQueue( pxQueue );
|
||||||
|
if( xTaskResumeAll() == pdFALSE )
|
||||||
|
{
|
||||||
|
portYIELD_WITHIN_API();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* There is data in the queue now, so don't enter the blocked
|
||||||
|
state, instead return to try and obtain the data. */
|
||||||
|
prvUnlockQueue( pxQueue );
|
||||||
|
( void ) xTaskResumeAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The timeout has expired. If there is still no data in the queue
|
||||||
|
exit, otherwise go back and try to read the data again. */
|
||||||
prvUnlockQueue( pxQueue );
|
prvUnlockQueue( pxQueue );
|
||||||
( void ) xTaskResumeAll();
|
( void ) xTaskResumeAll();
|
||||||
|
|
||||||
|
@ -1468,7 +1826,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
|
traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
|
||||||
|
|
||||||
prvCopyDataFromQueue( pxQueue, pvBuffer );
|
prvCopyDataFromQueue( pxQueue, pvBuffer );
|
||||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
|
pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
|
||||||
|
|
||||||
/* If the queue is locked the event list will not be modified.
|
/* If the queue is locked the event list will not be modified.
|
||||||
Instead update the lock count so the task that unlocks the queue
|
Instead update the lock count so the task that unlocks the queue
|
||||||
|
@ -1694,6 +2052,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||||
#endif /* configUSE_TRACE_FACILITY */
|
#endif /* configUSE_TRACE_FACILITY */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( configUSE_MUTEXES == 1 )
|
||||||
|
|
||||||
|
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue )
|
||||||
|
{
|
||||||
|
UBaseType_t uxHighestPriorityOfWaitingTasks;
|
||||||
|
|
||||||
|
/* If a task waiting for a mutex causes the mutex holder to inherit a
|
||||||
|
priority, but the waiting task times out, then the holder should
|
||||||
|
disinherit the priority - but only down to the highest priority of any
|
||||||
|
other tasks that are waiting for the same mutex. For this purpose,
|
||||||
|
return the priority of the highest priority task that is waiting for the
|
||||||
|
mutex. */
|
||||||
|
if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0 )
|
||||||
|
{
|
||||||
|
uxHighestPriorityOfWaitingTasks = configMAX_PRIORITIES - listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uxHighestPriorityOfWaitingTasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
|
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
|
||||||
{
|
{
|
||||||
BaseType_t xReturn = pdFALSE;
|
BaseType_t xReturn = pdFALSE;
|
||||||
|
@ -1767,7 +2152,7 @@ UBaseType_t uxMessagesWaiting;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;
|
pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
|
||||||
|
|
||||||
return xReturn;
|
return xReturn;
|
||||||
}
|
}
|
||||||
|
@ -2316,7 +2701,7 @@ BaseType_t xReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcReturn;
|
return pcReturn;
|
||||||
}
|
} /*lint !e818 xQueue cannot be a pointer to const because it is a typedef. */
|
||||||
|
|
||||||
#endif /* configQUEUE_REGISTRY_SIZE */
|
#endif /* configQUEUE_REGISTRY_SIZE */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
@ -2395,7 +2780,7 @@ BaseType_t xReturn;
|
||||||
{
|
{
|
||||||
QueueSetHandle_t pxQueue;
|
QueueSetHandle_t pxQueue;
|
||||||
|
|
||||||
pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( Queue_t * ), queueQUEUE_TYPE_SET );
|
pxQueue = xQueueGenericCreate( uxEventQueueLength, ( UBaseType_t ) sizeof( Queue_t * ), queueQUEUE_TYPE_SET );
|
||||||
|
|
||||||
return pxQueue;
|
return pxQueue;
|
||||||
}
|
}
|
||||||
|
@ -2478,7 +2863,7 @@ BaseType_t xReturn;
|
||||||
{
|
{
|
||||||
QueueSetMemberHandle_t xReturn = NULL;
|
QueueSetMemberHandle_t xReturn = NULL;
|
||||||
|
|
||||||
( void ) xQueueGenericReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */
|
( void ) xQueueReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait ); /*lint !e961 Casting from one typedef to another is not redundant. */
|
||||||
return xReturn;
|
return xReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
Each real time kernel port consists of three files that contain the core kernel
|
Each real time kernel port consists of three files that contain the core kernel
|
||||||
components and are common to every port, and one or more files that are
|
components and are common to every port, and one or more files that are
|
||||||
specific to a particular microcontroller and or compiler.
|
specific to a particular microcontroller and/or compiler.
|
||||||
|
|
||||||
+ The FreeRTOS/Source directory contains the three files that are common to
|
|
||||||
every port - list.c, queue.c and tasks.c. The kernel is contained within these
|
|
||||||
three files. croutine.c implements the optional co-routine functionality - which
|
|
||||||
is normally only used on very memory limited systems.
|
|
||||||
|
|
||||||
+ The FreeRTOS/Source/Portable directory contains the files that are specific to
|
+ The FreeRTOS/Source/Portable/MemMang directory contains the five sample
|
||||||
a particular microcontroller and or compiler.
|
memory allocators as described on the http://www.FreeRTOS.org WEB site.
|
||||||
|
|
||||||
+ The FreeRTOS/Source/include directory contains the real time kernel header
|
+ The other directories each contain files specific to a particular
|
||||||
files.
|
microcontroller or compiler, where the directory name denotes the compiler
|
||||||
|
specific files the directory contains.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
For example, if you are interested in the [compiler] port for the [architecture]
|
||||||
|
microcontroller, then the port specific files are contained in
|
||||||
|
FreeRTOS/Source/Portable/[compiler]/[architecture] directory. If this is the
|
||||||
|
only port you are interested in then all the other directories can be
|
||||||
|
ignored.
|
||||||
|
|
||||||
See the readme file in the FreeRTOS/Source/Portable directory for more
|
|
||||||
information.
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -131,12 +131,23 @@ made to free the RAM that was allocated statically.
|
||||||
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a
|
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a
|
||||||
task to be created using either statically or dynamically allocated RAM. Note
|
task to be created using either statically or dynamically allocated RAM. Note
|
||||||
that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
|
that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
|
||||||
a statically allocated stack and a dynamically allocated TCB. */
|
a statically allocated stack and a dynamically allocated TCB.
|
||||||
#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
|
!!!NOTE!!! If the definition of tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is
|
||||||
|
changed then the definition of StaticTask_t must also be updated. */
|
||||||
|
#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||||
#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
|
#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
|
||||||
#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
|
#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
|
||||||
#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
|
#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
|
||||||
|
|
||||||
|
/* If any of the following are set then task stacks are filled with a known
|
||||||
|
value so the high water mark can be determined. If none of the following are
|
||||||
|
set then don't fill the stack so there is no unnecessary dependency on memset. */
|
||||||
|
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
||||||
|
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
|
||||||
|
#else
|
||||||
|
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Macros used by vListTask to indicate which state a task is in.
|
* Macros used by vListTask to indicate which state a task is in.
|
||||||
*/
|
*/
|
||||||
|
@ -153,6 +164,12 @@ a statically allocated stack and a dynamically allocated TCB. */
|
||||||
#define static
|
#define static
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The name allocated to the Idle task. This can be overridden by defining
|
||||||
|
configIDLE_TASK_NAME in FreeRTOSConfig.h. */
|
||||||
|
#ifndef configIDLE_TASK_NAME
|
||||||
|
#define configIDLE_TASK_NAME "IDLE"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
|
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
|
||||||
|
|
||||||
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
|
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
|
||||||
|
@ -304,8 +321,8 @@ typedef struct tskTaskControlBlock
|
||||||
StackType_t *pxStack; /*< Points to the start of the stack. */
|
StackType_t *pxStack; /*< Points to the start of the stack. */
|
||||||
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
|
|
||||||
#if ( portSTACK_GROWTH > 0 )
|
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||||
StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */
|
StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||||
|
@ -327,7 +344,7 @@ typedef struct tskTaskControlBlock
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
|
#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
|
||||||
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if( configGENERATE_RUN_TIME_STATS == 1 )
|
#if( configGENERATE_RUN_TIME_STATS == 1 )
|
||||||
|
@ -352,7 +369,7 @@ typedef struct tskTaskControlBlock
|
||||||
|
|
||||||
/* See the comments above the definition of
|
/* See the comments above the definition of
|
||||||
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
|
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
|
||||||
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
|
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
|
||||||
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
|
uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -366,8 +383,8 @@ typedef struct tskTaskControlBlock
|
||||||
below to enable the use of older kernel aware debuggers. */
|
below to enable the use of older kernel aware debuggers. */
|
||||||
typedef tskTCB TCB_t;
|
typedef tskTCB TCB_t;
|
||||||
|
|
||||||
/*lint -e956 A manual analysis and inspection has been used to determine which
|
/*lint -save -e956 A manual analysis and inspection has been used to determine
|
||||||
static variables must be declared volatile. */
|
which static variables must be declared volatile. */
|
||||||
|
|
||||||
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
|
PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
|
||||||
|
|
||||||
|
@ -394,7 +411,7 @@ PRIVILEGED_DATA static List_t xPendingReadyList; /*< Tasks that have been r
|
||||||
|
|
||||||
/* Other file private variables. --------------------------------*/
|
/* Other file private variables. --------------------------------*/
|
||||||
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
|
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U;
|
||||||
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) 0U;
|
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;
|
||||||
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
|
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;
|
||||||
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
|
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;
|
||||||
PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
|
PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks = ( UBaseType_t ) 0U;
|
||||||
|
@ -421,21 +438,27 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*lint +e956 */
|
/*lint -restore */
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
/* Callback function prototypes. --------------------------*/
|
/* Callback function prototypes. --------------------------*/
|
||||||
#if( configCHECK_FOR_STACK_OVERFLOW > 0 )
|
#if( configCHECK_FOR_STACK_OVERFLOW > 0 )
|
||||||
|
|
||||||
extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
|
extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if( configUSE_TICK_HOOK > 0 )
|
#if( configUSE_TICK_HOOK > 0 )
|
||||||
|
|
||||||
extern void vApplicationTickHook( void );
|
extern void vApplicationTickHook( void );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
|
extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* File private functions. --------------------------------*/
|
/* File private functions. --------------------------------*/
|
||||||
|
@ -446,7 +469,9 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
|
||||||
* is in any other state.
|
* is in any other state.
|
||||||
*/
|
*/
|
||||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
#if ( INCLUDE_vTaskSuspend == 1 )
|
||||||
|
|
||||||
static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
#endif /* INCLUDE_vTaskSuspend */
|
#endif /* INCLUDE_vTaskSuspend */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -565,13 +590,13 @@ static void prvResetNextTaskUnblockTime( void );
|
||||||
* dynamically to fill in the structure's members.
|
* dynamically to fill in the structure's members.
|
||||||
*/
|
*/
|
||||||
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const uint32_t ulStackDepth,
|
const uint32_t ulStackDepth,
|
||||||
void * const pvParameters,
|
void * const pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
TaskHandle_t * const pxCreatedTask,
|
TaskHandle_t * const pxCreatedTask,
|
||||||
TCB_t *pxNewTCB,
|
TCB_t *pxNewTCB,
|
||||||
const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Called after a new task has been created and initialised to place the task
|
* Called after a new task has been created and initialised to place the task
|
||||||
|
@ -579,17 +604,28 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
||||||
*/
|
*/
|
||||||
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* freertos_tasks_c_additions_init() should only be called if the user definable
|
||||||
|
* macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
|
||||||
|
* called by the function.
|
||||||
|
*/
|
||||||
|
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
|
||||||
|
|
||||||
|
static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
|
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const uint32_t ulStackDepth,
|
const uint32_t ulStackDepth,
|
||||||
void * const pvParameters,
|
void * const pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
StackType_t * const puxStackBuffer,
|
StackType_t * const puxStackBuffer,
|
||||||
StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
StaticTask_t * const pxTaskBuffer )
|
||||||
{
|
{
|
||||||
TCB_t *pxNewTCB;
|
TCB_t *pxNewTCB;
|
||||||
TaskHandle_t xReturn;
|
TaskHandle_t xReturn;
|
||||||
|
@ -597,6 +633,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
configASSERT( puxStackBuffer != NULL );
|
configASSERT( puxStackBuffer != NULL );
|
||||||
configASSERT( pxTaskBuffer != NULL );
|
configASSERT( pxTaskBuffer != NULL );
|
||||||
|
|
||||||
|
#if( configASSERT_DEFINED == 1 )
|
||||||
|
{
|
||||||
|
/* Sanity check that the size of the structure used to declare a
|
||||||
|
variable of type StaticTask_t equals the size of the real task
|
||||||
|
structure. */
|
||||||
|
volatile size_t xSize = sizeof( StaticTask_t );
|
||||||
|
configASSERT( xSize == sizeof( TCB_t ) );
|
||||||
|
}
|
||||||
|
#endif /* configASSERT_DEFINED */
|
||||||
|
|
||||||
|
|
||||||
if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
|
if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
|
||||||
{
|
{
|
||||||
/* The memory used for the task's TCB and stack are passed into this
|
/* The memory used for the task's TCB and stack are passed into this
|
||||||
|
@ -604,7 +651,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
|
pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
|
||||||
pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
|
pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
|
||||||
|
|
||||||
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
|
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
|
||||||
{
|
{
|
||||||
/* Tasks can be created statically or dynamically, so note this
|
/* Tasks can be created statically or dynamically, so note this
|
||||||
task was created statically in case the task is later deleted. */
|
task was created statically in case the task is later deleted. */
|
||||||
|
@ -626,7 +673,53 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
#endif /* SUPPORT_STATIC_ALLOCATION */
|
#endif /* SUPPORT_STATIC_ALLOCATION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if( portUSING_MPU_WRAPPERS == 1 )
|
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
|
||||||
|
|
||||||
|
BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
|
||||||
|
{
|
||||||
|
TCB_t *pxNewTCB;
|
||||||
|
BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
||||||
|
|
||||||
|
configASSERT( pxTaskDefinition->puxStackBuffer != NULL );
|
||||||
|
configASSERT( pxTaskDefinition->pxTaskBuffer != NULL );
|
||||||
|
|
||||||
|
if( ( pxTaskDefinition->puxStackBuffer != NULL ) && ( pxTaskDefinition->pxTaskBuffer != NULL ) )
|
||||||
|
{
|
||||||
|
/* Allocate space for the TCB. Where the memory comes from depends
|
||||||
|
on the implementation of the port malloc function and whether or
|
||||||
|
not static allocation is being used. */
|
||||||
|
pxNewTCB = ( TCB_t * ) pxTaskDefinition->pxTaskBuffer;
|
||||||
|
|
||||||
|
/* Store the stack location in the TCB. */
|
||||||
|
pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
|
||||||
|
|
||||||
|
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
|
||||||
|
{
|
||||||
|
/* Tasks can be created statically or dynamically, so note this
|
||||||
|
task was created statically in case the task is later deleted. */
|
||||||
|
pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
|
||||||
|
}
|
||||||
|
#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
||||||
|
|
||||||
|
prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
|
||||||
|
pxTaskDefinition->pcName,
|
||||||
|
( uint32_t ) pxTaskDefinition->usStackDepth,
|
||||||
|
pxTaskDefinition->pvParameters,
|
||||||
|
pxTaskDefinition->uxPriority,
|
||||||
|
pxCreatedTask, pxNewTCB,
|
||||||
|
pxTaskDefinition->xRegions );
|
||||||
|
|
||||||
|
prvAddNewTaskToReadyList( pxNewTCB );
|
||||||
|
xReturn = pdPASS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) )
|
||||||
|
|
||||||
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
|
BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
|
||||||
{
|
{
|
||||||
|
@ -674,11 +767,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const uint16_t usStackDepth,
|
const configSTACK_DEPTH_TYPE usStackDepth,
|
||||||
void * const pvParameters,
|
void * const pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
TaskHandle_t * const pxCreatedTask )
|
||||||
{
|
{
|
||||||
TCB_t *pxNewTCB;
|
TCB_t *pxNewTCB;
|
||||||
BaseType_t xReturn;
|
BaseType_t xReturn;
|
||||||
|
@ -741,7 +834,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
|
|
||||||
if( pxNewTCB != NULL )
|
if( pxNewTCB != NULL )
|
||||||
{
|
{
|
||||||
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
|
#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
|
||||||
{
|
{
|
||||||
/* Tasks can be created statically or dynamically, so note this
|
/* Tasks can be created statically or dynamically, so note this
|
||||||
task was created dynamically in case it is later deleted. */
|
task was created dynamically in case it is later deleted. */
|
||||||
|
@ -765,13 +858,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
||||||
const char * const pcName,
|
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const uint32_t ulStackDepth,
|
const uint32_t ulStackDepth,
|
||||||
void * const pvParameters,
|
void * const pvParameters,
|
||||||
UBaseType_t uxPriority,
|
UBaseType_t uxPriority,
|
||||||
TaskHandle_t * const pxCreatedTask,
|
TaskHandle_t * const pxCreatedTask,
|
||||||
TCB_t *pxNewTCB,
|
TCB_t *pxNewTCB,
|
||||||
const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
const MemoryRegion_t * const xRegions )
|
||||||
{
|
{
|
||||||
StackType_t *pxTopOfStack;
|
StackType_t *pxTopOfStack;
|
||||||
UBaseType_t x;
|
UBaseType_t x;
|
||||||
|
@ -791,12 +884,12 @@ UBaseType_t x;
|
||||||
#endif /* portUSING_MPU_WRAPPERS == 1 */
|
#endif /* portUSING_MPU_WRAPPERS == 1 */
|
||||||
|
|
||||||
/* Avoid dependency on memset() if it is not required. */
|
/* Avoid dependency on memset() if it is not required. */
|
||||||
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
#if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
|
||||||
{
|
{
|
||||||
/* Fill the stack with a known value to assist debugging. */
|
/* Fill the stack with a known value to assist debugging. */
|
||||||
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
|
( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
|
||||||
}
|
}
|
||||||
#endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
|
#endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
|
||||||
|
|
||||||
/* Calculate the top of stack address. This depends on whether the stack
|
/* Calculate the top of stack address. This depends on whether the stack
|
||||||
grows from high memory to low (as per the 80x86) or vice versa.
|
grows from high memory to low (as per the 80x86) or vice versa.
|
||||||
|
@ -809,6 +902,14 @@ UBaseType_t x;
|
||||||
|
|
||||||
/* Check the alignment of the calculated top of stack is correct. */
|
/* Check the alignment of the calculated top of stack is correct. */
|
||||||
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
|
configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
|
||||||
|
|
||||||
|
#if( configRECORD_STACK_HIGH_ADDRESS == 1 )
|
||||||
|
{
|
||||||
|
/* Also record the stack's high address, which may assist
|
||||||
|
debugging. */
|
||||||
|
pxNewTCB->pxEndOfStack = pxTopOfStack;
|
||||||
|
}
|
||||||
|
#endif /* configRECORD_STACK_HIGH_ADDRESS */
|
||||||
}
|
}
|
||||||
#else /* portSTACK_GROWTH */
|
#else /* portSTACK_GROWTH */
|
||||||
{
|
{
|
||||||
|
@ -936,7 +1037,7 @@ UBaseType_t x;
|
||||||
/* Initialize the TCB stack to look as if the task was already running,
|
/* 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
|
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
|
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 )
|
#if( portUSING_MPU_WRAPPERS == 1 )
|
||||||
{
|
{
|
||||||
pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
|
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
|
/* If the task is in the blocked or suspended list we need do
|
||||||
nothing more than change it's priority variable. However, if
|
nothing more than change its priority variable. However, if
|
||||||
the task is in a ready list it needs to be removed and placed
|
the task is in a ready list it needs to be removed and placed
|
||||||
in the list appropriate to its new priority. */
|
in the list appropriate to its new priority. */
|
||||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
||||||
{
|
{
|
||||||
/* The task is currently in its ready list - remove before adding
|
/* The task is currently in its ready list - remove before
|
||||||
it to it's new ready list. As we are in a critical section we
|
adding it to it's new ready list. As we are in a critical
|
||||||
can do this even if the scheduler is suspended. */
|
section we can do this even if the scheduler is suspended. */
|
||||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
/* It is known that the task is in its ready list so
|
/* It is known that the task is in its ready list so
|
||||||
|
@ -1597,6 +1698,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
||||||
}
|
}
|
||||||
|
|
||||||
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
|
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
|
||||||
|
|
||||||
|
#if( configUSE_TASK_NOTIFICATIONS == 1 )
|
||||||
|
{
|
||||||
|
if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
|
||||||
|
{
|
||||||
|
/* The task was blocked to wait for a notification, but is
|
||||||
|
now suspended, so no notification was received. */
|
||||||
|
pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
@ -1672,7 +1784,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
||||||
{
|
{
|
||||||
/* Is it in the suspended list because it is in the Suspended
|
/* Is it in the suspended list because it is in the Suspended
|
||||||
state, or because is is blocked with no timeout? */
|
state, or because is is blocked with no timeout? */
|
||||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
|
if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) /*lint !e961. The cast is only redundant when NULL is used. */
|
||||||
{
|
{
|
||||||
xReturn = pdTRUE;
|
xReturn = pdTRUE;
|
||||||
}
|
}
|
||||||
|
@ -1716,12 +1828,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
|
||||||
{
|
{
|
||||||
traceTASK_RESUME( pxTCB );
|
traceTASK_RESUME( pxTCB );
|
||||||
|
|
||||||
/* As we are in a critical section we can access the ready
|
/* The ready list can be accessed even if the scheduler is
|
||||||
lists even if the scheduler is suspended. */
|
suspended because this is inside a critical section. */
|
||||||
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
||||||
prvAddTaskToReadyList( pxTCB );
|
prvAddTaskToReadyList( pxTCB );
|
||||||
|
|
||||||
/* We may have just resumed a higher priority task. */
|
/* A higher priority task may have just been resumed. */
|
||||||
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
|
||||||
{
|
{
|
||||||
/* This yield may not cause the task just resumed to run,
|
/* This yield may not cause the task just resumed to run,
|
||||||
|
@ -1838,9 +1950,9 @@ BaseType_t xReturn;
|
||||||
address of the RAM then create the idle task. */
|
address of the RAM then create the idle task. */
|
||||||
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
|
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
|
||||||
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
|
xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
|
||||||
"IDLE",
|
configIDLE_TASK_NAME,
|
||||||
ulIdleTaskStackSize,
|
ulIdleTaskStackSize,
|
||||||
( void * ) NULL,
|
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
|
||||||
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
||||||
pxIdleTaskStackBuffer,
|
pxIdleTaskStackBuffer,
|
||||||
pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
||||||
|
@ -1858,7 +1970,8 @@ BaseType_t xReturn;
|
||||||
{
|
{
|
||||||
/* The Idle task is being created using dynamically allocated RAM. */
|
/* The Idle task is being created using dynamically allocated RAM. */
|
||||||
xReturn = xTaskCreate( prvIdleTask,
|
xReturn = xTaskCreate( prvIdleTask,
|
||||||
"IDLE", configMINIMAL_STACK_SIZE,
|
configIDLE_TASK_NAME,
|
||||||
|
configMINIMAL_STACK_SIZE,
|
||||||
( void * ) NULL,
|
( void * ) NULL,
|
||||||
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
|
||||||
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
|
||||||
|
@ -1880,6 +1993,15 @@ BaseType_t xReturn;
|
||||||
|
|
||||||
if( xReturn == pdPASS )
|
if( xReturn == pdPASS )
|
||||||
{
|
{
|
||||||
|
/* freertos_tasks_c_additions_init() should only be called if the user
|
||||||
|
definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is
|
||||||
|
the only macro called by the function. */
|
||||||
|
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
|
||||||
|
{
|
||||||
|
freertos_tasks_c_additions_init();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Interrupts are turned off here, to ensure a tick does not occur
|
/* Interrupts are turned off here, to ensure a tick does not occur
|
||||||
before or during the call to xPortStartScheduler(). The stacks of
|
before or during the call to xPortStartScheduler(). The stacks of
|
||||||
the created tasks contain a status word with interrupts switched on
|
the created tasks contain a status word with interrupts switched on
|
||||||
|
@ -1901,7 +2023,10 @@ BaseType_t xReturn;
|
||||||
|
|
||||||
/* If configGENERATE_RUN_TIME_STATS is defined then the following
|
/* If configGENERATE_RUN_TIME_STATS is defined then the following
|
||||||
macro must be defined to configure the timer/counter used to generate
|
macro must be defined to configure the timer/counter used to generate
|
||||||
the run time counter time base. */
|
the run time counter time base. NOTE: If configGENERATE_RUN_TIME_STATS
|
||||||
|
is set to 0 and the following line fails to build then ensure you do not
|
||||||
|
have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
|
||||||
|
FreeRTOSConfig.h file. */
|
||||||
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
|
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
|
||||||
|
|
||||||
/* Setting up the timer tick is hardware specific and thus in the
|
/* Setting up the timer tick is hardware specific and thus in the
|
||||||
|
@ -2427,7 +2552,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
||||||
BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
|
BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
|
||||||
{
|
{
|
||||||
TCB_t *pxTCB = ( TCB_t * ) xTask;
|
TCB_t *pxTCB = ( TCB_t * ) xTask;
|
||||||
BaseType_t xReturn = pdFALSE;
|
BaseType_t xReturn;
|
||||||
|
|
||||||
configASSERT( pxTCB );
|
configASSERT( pxTCB );
|
||||||
|
|
||||||
|
@ -2437,6 +2562,8 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
||||||
it is actually in the Blocked state. */
|
it is actually in the Blocked state. */
|
||||||
if( eTaskGetState( xTask ) == eBlocked )
|
if( eTaskGetState( xTask ) == eBlocked )
|
||||||
{
|
{
|
||||||
|
xReturn = pdPASS;
|
||||||
|
|
||||||
/* Remove the reference to the task from the blocked list. An
|
/* Remove the reference to the task from the blocked list. An
|
||||||
interrupt won't touch the xStateListItem because the
|
interrupt won't touch the xStateListItem because the
|
||||||
scheduler is suspended. */
|
scheduler is suspended. */
|
||||||
|
@ -2485,10 +2612,10 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mtCOVERAGE_TEST_MARKER();
|
xReturn = pdFAIL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xTaskResumeAll();
|
( void ) xTaskResumeAll();
|
||||||
|
|
||||||
return xReturn;
|
return xReturn;
|
||||||
}
|
}
|
||||||
|
@ -2510,13 +2637,13 @@ BaseType_t xSwitchRequired = pdFALSE;
|
||||||
{
|
{
|
||||||
/* Minor optimisation. The tick count cannot change in this
|
/* Minor optimisation. The tick count cannot change in this
|
||||||
block. */
|
block. */
|
||||||
const TickType_t xConstTickCount = xTickCount + 1;
|
const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
|
||||||
|
|
||||||
/* Increment the RTOS tick, switching the delayed and overflowed
|
/* Increment the RTOS tick, switching the delayed and overflowed
|
||||||
delayed lists if it wraps to 0. */
|
delayed lists if it wraps to 0. */
|
||||||
xTickCount = xConstTickCount;
|
xTickCount = xConstTickCount;
|
||||||
|
|
||||||
if( xConstTickCount == ( TickType_t ) 0U )
|
if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
|
||||||
{
|
{
|
||||||
taskSWITCH_DELAYED_LISTS();
|
taskSWITCH_DELAYED_LISTS();
|
||||||
}
|
}
|
||||||
|
@ -2959,10 +3086,9 @@ BaseType_t xReturn;
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
|
void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
|
||||||
{
|
{
|
||||||
TCB_t *pxUnblockedTCB;
|
TCB_t *pxUnblockedTCB;
|
||||||
BaseType_t xReturn;
|
|
||||||
|
|
||||||
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
|
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
|
||||||
the event flags implementation. */
|
the event flags implementation. */
|
||||||
|
@ -2985,28 +3111,30 @@ BaseType_t xReturn;
|
||||||
|
|
||||||
if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
|
if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
|
||||||
{
|
{
|
||||||
/* Return true if the task removed from the event list has
|
/* The unblocked task has a priority above that of the calling task, so
|
||||||
a higher priority than the calling task. This allows
|
a context switch is required. This function is called with the
|
||||||
the calling task to know if it should force a context
|
scheduler suspended so xYieldPending is set so the context switch
|
||||||
switch now. */
|
occurs immediately that the scheduler is resumed (unsuspended). */
|
||||||
xReturn = pdTRUE;
|
|
||||||
|
|
||||||
/* Mark that a yield is pending in case the user is not using the
|
|
||||||
"xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
|
|
||||||
xYieldPending = pdTRUE;
|
xYieldPending = pdTRUE;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
xReturn = pdFALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xReturn;
|
|
||||||
}
|
}
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
|
void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
|
||||||
{
|
{
|
||||||
configASSERT( pxTimeOut );
|
configASSERT( pxTimeOut );
|
||||||
|
taskENTER_CRITICAL();
|
||||||
|
{
|
||||||
|
pxTimeOut->xOverflowCount = xNumOfOverflows;
|
||||||
|
pxTimeOut->xTimeOnEntering = xTickCount;
|
||||||
|
}
|
||||||
|
taskEXIT_CRITICAL();
|
||||||
|
}
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut )
|
||||||
|
{
|
||||||
|
/* For internal use only as it does not use a critical section. */
|
||||||
pxTimeOut->xOverflowCount = xNumOfOverflows;
|
pxTimeOut->xOverflowCount = xNumOfOverflows;
|
||||||
pxTimeOut->xTimeOnEntering = xTickCount;
|
pxTimeOut->xTimeOnEntering = xTickCount;
|
||||||
}
|
}
|
||||||
|
@ -3023,6 +3151,7 @@ BaseType_t xReturn;
|
||||||
{
|
{
|
||||||
/* Minor optimisation. The tick count cannot change in this block. */
|
/* Minor optimisation. The tick count cannot change in this block. */
|
||||||
const TickType_t xConstTickCount = xTickCount;
|
const TickType_t xConstTickCount = xTickCount;
|
||||||
|
const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
|
||||||
|
|
||||||
#if( INCLUDE_xTaskAbortDelay == 1 )
|
#if( INCLUDE_xTaskAbortDelay == 1 )
|
||||||
if( pxCurrentTCB->ucDelayAborted != pdFALSE )
|
if( pxCurrentTCB->ucDelayAborted != pdFALSE )
|
||||||
|
@ -3055,11 +3184,11 @@ BaseType_t xReturn;
|
||||||
was called. */
|
was called. */
|
||||||
xReturn = pdTRUE;
|
xReturn = pdTRUE;
|
||||||
}
|
}
|
||||||
else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
|
else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
|
||||||
{
|
{
|
||||||
/* Not a genuine timeout. Adjust parameters for time remaining. */
|
/* Not a genuine timeout. Adjust parameters for time remaining. */
|
||||||
*pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
|
*pxTicksToWait -= xElapsedTime;
|
||||||
vTaskSetTimeOutState( pxTimeOut );
|
vTaskInternalSetTimeOutState( pxTimeOut );
|
||||||
xReturn = pdFALSE;
|
xReturn = pdFALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3136,6 +3265,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||||
/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
|
/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
|
||||||
SCHEDULER IS STARTED. **/
|
SCHEDULER IS STARTED. **/
|
||||||
|
|
||||||
|
/* In case a task that has a secure context deletes itself, in which case
|
||||||
|
the idle task is responsible for deleting the task's secure context, if
|
||||||
|
any. */
|
||||||
|
portTASK_CALLS_SECURE_FUNCTIONS();
|
||||||
|
|
||||||
for( ;; )
|
for( ;; )
|
||||||
{
|
{
|
||||||
/* See if any tasks have deleted themselves - if so then the idle task
|
/* See if any tasks have deleted themselves - if so then the idle task
|
||||||
|
@ -3212,6 +3346,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||||
configASSERT( xNextTaskUnblockTime >= xTickCount );
|
configASSERT( xNextTaskUnblockTime >= xTickCount );
|
||||||
xExpectedIdleTime = prvGetExpectedIdleTime();
|
xExpectedIdleTime = prvGetExpectedIdleTime();
|
||||||
|
|
||||||
|
/* Define the following macro to set xExpectedIdleTime to 0
|
||||||
|
if the application does not want
|
||||||
|
portSUPPRESS_TICKS_AND_SLEEP() to be called. */
|
||||||
|
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
|
||||||
|
|
||||||
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
|
if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
|
||||||
{
|
{
|
||||||
traceLOW_POWER_IDLE_BEGIN();
|
traceLOW_POWER_IDLE_BEGIN();
|
||||||
|
@ -3369,37 +3508,22 @@ static void prvCheckTasksWaitingTermination( void )
|
||||||
|
|
||||||
#if ( INCLUDE_vTaskDelete == 1 )
|
#if ( INCLUDE_vTaskDelete == 1 )
|
||||||
{
|
{
|
||||||
BaseType_t xListIsEmpty;
|
TCB_t *pxTCB;
|
||||||
|
|
||||||
/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
|
/* uxDeletedTasksWaitingCleanUp is used to prevent vTaskSuspendAll()
|
||||||
too often in the idle task. */
|
being called too often in the idle task. */
|
||||||
while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
|
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 )
|
prvDeleteTCB( pxTCB );
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* INCLUDE_vTaskDelete */
|
#endif /* INCLUDE_vTaskDelete */
|
||||||
|
@ -3421,25 +3545,6 @@ static void prvCheckTasksWaitingTermination( void )
|
||||||
pxTaskStatus->pxStackBase = pxTCB->pxStack;
|
pxTaskStatus->pxStackBase = pxTCB->pxStack;
|
||||||
pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
|
pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
|
||||||
|
|
||||||
#if ( INCLUDE_vTaskSuspend == 1 )
|
|
||||||
{
|
|
||||||
/* If the task is in the suspended list then there is a chance it is
|
|
||||||
actually just blocked indefinitely - so really it should be reported as
|
|
||||||
being in the Blocked state. */
|
|
||||||
if( pxTaskStatus->eCurrentState == eSuspended )
|
|
||||||
{
|
|
||||||
vTaskSuspendAll();
|
|
||||||
{
|
|
||||||
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
|
|
||||||
{
|
|
||||||
pxTaskStatus->eCurrentState = eBlocked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
xTaskResumeAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* INCLUDE_vTaskSuspend */
|
|
||||||
|
|
||||||
#if ( configUSE_MUTEXES == 1 )
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
{
|
{
|
||||||
pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
|
pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
|
||||||
|
@ -3460,12 +3565,38 @@ static void prvCheckTasksWaitingTermination( void )
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Obtaining the task state is a little fiddly, so is only done if the value
|
/* Obtaining the task state is a little fiddly, so is only done if the
|
||||||
of eState passed into this function is eInvalid - otherwise the state is
|
value of eState passed into this function is eInvalid - otherwise the
|
||||||
just set to whatever is passed in. */
|
state is just set to whatever is passed in. */
|
||||||
if( eState != eInvalid )
|
if( eState != eInvalid )
|
||||||
{
|
{
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -3499,7 +3630,7 @@ static void prvCheckTasksWaitingTermination( void )
|
||||||
|
|
||||||
static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
|
static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
|
||||||
{
|
{
|
||||||
volatile TCB_t *pxNextTCB, *pxFirstTCB;
|
configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB;
|
||||||
UBaseType_t uxTask = 0;
|
UBaseType_t uxTask = 0;
|
||||||
|
|
||||||
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
|
if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
|
||||||
|
@ -3600,7 +3731,7 @@ static void prvCheckTasksWaitingTermination( void )
|
||||||
vPortFree( pxTCB->pxStack );
|
vPortFree( pxTCB->pxStack );
|
||||||
vPortFree( pxTCB );
|
vPortFree( pxTCB );
|
||||||
}
|
}
|
||||||
#elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )
|
#elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
|
||||||
{
|
{
|
||||||
/* The task could have been allocated statically or dynamically, so
|
/* The task could have been allocated statically or dynamically, so
|
||||||
check what was statically allocated before trying to free the
|
check what was statically allocated before trying to free the
|
||||||
|
@ -3622,7 +3753,7 @@ static void prvCheckTasksWaitingTermination( void )
|
||||||
{
|
{
|
||||||
/* Neither the stack nor the TCB were allocated dynamically, so
|
/* Neither the stack nor the TCB were allocated dynamically, so
|
||||||
nothing needs to be freed. */
|
nothing needs to be freed. */
|
||||||
configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB )
|
configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB );
|
||||||
mtCOVERAGE_TEST_MARKER();
|
mtCOVERAGE_TEST_MARKER();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3703,25 +3834,27 @@ TCB_t *pxTCB;
|
||||||
|
|
||||||
#if ( configUSE_MUTEXES == 1 )
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
|
|
||||||
void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
|
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
|
||||||
{
|
{
|
||||||
TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
|
TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;
|
||||||
|
BaseType_t xReturn = pdFALSE;
|
||||||
|
|
||||||
/* If the mutex was given back by an interrupt while the queue was
|
/* If the mutex was given back by an interrupt while the queue was
|
||||||
locked then the mutex holder might now be NULL. */
|
locked then the mutex holder might now be NULL. _RB_ Is this still
|
||||||
|
needed as interrupts can no longer use mutexes? */
|
||||||
if( pxMutexHolder != NULL )
|
if( pxMutexHolder != NULL )
|
||||||
{
|
{
|
||||||
/* If the holder of the mutex has a priority below the priority of
|
/* If the holder of the mutex has a priority below the priority of
|
||||||
the task attempting to obtain the mutex then it will temporarily
|
the task attempting to obtain the mutex then it will temporarily
|
||||||
inherit the priority of the task attempting to obtain the mutex. */
|
inherit the priority of the task attempting to obtain the mutex. */
|
||||||
if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
|
if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
|
||||||
{
|
{
|
||||||
/* Adjust the mutex holder state to account for its new
|
/* Adjust the mutex holder state to account for its new
|
||||||
priority. Only reset the event list item value if the value is
|
priority. Only reset the event list item value if the value is
|
||||||
not being used for anything else. */
|
not being used for anything else. */
|
||||||
if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
|
if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
|
||||||
{
|
{
|
||||||
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3730,11 +3863,11 @@ TCB_t *pxTCB;
|
||||||
|
|
||||||
/* If the task being modified is in the ready state it will need
|
/* If the task being modified is in the ready state it will need
|
||||||
to be moved into a new list. */
|
to be moved into a new list. */
|
||||||
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
|
||||||
{
|
{
|
||||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3742,26 +3875,45 @@ TCB_t *pxTCB;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Inherit the priority before being moved into the new list. */
|
/* Inherit the priority before being moved into the new list. */
|
||||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||||
prvAddTaskToReadyList( pxTCB );
|
prvAddTaskToReadyList( pxMutexHolderTCB );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Just inherit the priority. */
|
/* Just inherit the priority. */
|
||||||
pxTCB->uxPriority = pxCurrentTCB->uxPriority;
|
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
|
||||||
}
|
}
|
||||||
|
|
||||||
traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
|
traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );
|
||||||
|
|
||||||
|
/* Inheritance occurred. */
|
||||||
|
xReturn = pdTRUE;
|
||||||
}
|
}
|
||||||
else
|
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
|
else
|
||||||
{
|
{
|
||||||
mtCOVERAGE_TEST_MARKER();
|
mtCOVERAGE_TEST_MARKER();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return xReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* configUSE_MUTEXES */
|
#endif /* configUSE_MUTEXES */
|
||||||
|
@ -3781,7 +3933,6 @@ TCB_t *pxTCB;
|
||||||
interrupt, and if a mutex is given by the holding task then it must
|
interrupt, and if a mutex is given by the holding task then it must
|
||||||
be the running state task. */
|
be the running state task. */
|
||||||
configASSERT( pxTCB == pxCurrentTCB );
|
configASSERT( pxTCB == pxCurrentTCB );
|
||||||
|
|
||||||
configASSERT( pxTCB->uxMutexesHeld );
|
configASSERT( pxTCB->uxMutexesHeld );
|
||||||
( pxTCB->uxMutexesHeld )--;
|
( pxTCB->uxMutexesHeld )--;
|
||||||
|
|
||||||
|
@ -3795,8 +3946,8 @@ TCB_t *pxTCB;
|
||||||
/* A task can only have an inherited priority if it holds
|
/* 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
|
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
|
given from an interrupt, and if a mutex is given by the
|
||||||
holding task then it must be the running state task. Remove
|
holding task then it must be the running state task. Remove
|
||||||
the holding task from the ready list. */
|
the holding task from the ready list. */
|
||||||
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
{
|
{
|
||||||
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
||||||
|
@ -3848,6 +3999,108 @@ TCB_t *pxTCB;
|
||||||
#endif /* configUSE_MUTEXES */
|
#endif /* configUSE_MUTEXES */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if ( configUSE_MUTEXES == 1 )
|
||||||
|
|
||||||
|
void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )
|
||||||
|
{
|
||||||
|
TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
|
||||||
|
UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;
|
||||||
|
const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;
|
||||||
|
|
||||||
|
if( pxMutexHolder != NULL )
|
||||||
|
{
|
||||||
|
/* If pxMutexHolder is not NULL then the holder must hold at least
|
||||||
|
one mutex. */
|
||||||
|
configASSERT( pxTCB->uxMutexesHeld );
|
||||||
|
|
||||||
|
/* Determine the priority to which the priority of the task that
|
||||||
|
holds the mutex should be set. This will be the greater of the
|
||||||
|
holding task's base priority and the priority of the highest
|
||||||
|
priority task that is waiting to obtain the mutex. */
|
||||||
|
if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask )
|
||||||
|
{
|
||||||
|
uxPriorityToUse = uxHighestPriorityWaitingTask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uxPriorityToUse = pxTCB->uxBasePriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does the priority need to change? */
|
||||||
|
if( pxTCB->uxPriority != uxPriorityToUse )
|
||||||
|
{
|
||||||
|
/* Only disinherit if no other mutexes are held. This is a
|
||||||
|
simplification in the priority inheritance implementation. If
|
||||||
|
the task that holds the mutex is also holding other mutexes then
|
||||||
|
the other mutexes may have caused the priority inheritance. */
|
||||||
|
if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld )
|
||||||
|
{
|
||||||
|
/* If a task has timed out because it already holds the
|
||||||
|
mutex it was trying to obtain then it cannot of inherited
|
||||||
|
its own priority. */
|
||||||
|
configASSERT( pxTCB != pxCurrentTCB );
|
||||||
|
|
||||||
|
/* Disinherit the priority, remembering the previous
|
||||||
|
priority to facilitate determining the subject task's
|
||||||
|
state. */
|
||||||
|
traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
|
||||||
|
uxPriorityUsedOnEntry = pxTCB->uxPriority;
|
||||||
|
pxTCB->uxPriority = uxPriorityToUse;
|
||||||
|
|
||||||
|
/* Only reset the event list item value if the value is not
|
||||||
|
being used for anything else. */
|
||||||
|
if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
|
||||||
|
{
|
||||||
|
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the running task is not the task that holds the mutex
|
||||||
|
then the task that holds the mutex could be in either the
|
||||||
|
Ready, Blocked or Suspended states. Only remove the task
|
||||||
|
from its current state list if it is in the Ready state as
|
||||||
|
the task's priority is going to change and there is one
|
||||||
|
Ready list per priority. */
|
||||||
|
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
|
||||||
|
{
|
||||||
|
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
|
||||||
|
{
|
||||||
|
taskRESET_READY_PRIORITY( pxTCB->uxPriority );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
|
||||||
|
prvAddTaskToReadyList( pxTCB );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mtCOVERAGE_TEST_MARKER();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* configUSE_MUTEXES */
|
||||||
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
||||||
|
|
||||||
void vTaskEnterCritical( void )
|
void vTaskEnterCritical( void )
|
||||||
|
@ -3937,7 +4190,7 @@ TCB_t *pxTCB;
|
||||||
#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
|
#endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
|
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||||
|
|
||||||
void vTaskList( char * pcWriteBuffer )
|
void vTaskList( char * pcWriteBuffer )
|
||||||
{
|
{
|
||||||
|
@ -4029,10 +4282,10 @@ TCB_t *pxTCB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
|
#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */
|
||||||
/*----------------------------------------------------------*/
|
/*----------------------------------------------------------*/
|
||||||
|
|
||||||
#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
|
#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
|
||||||
|
|
||||||
void vTaskGetRunTimeStats( char *pcWriteBuffer )
|
void vTaskGetRunTimeStats( char *pcWriteBuffer )
|
||||||
{
|
{
|
||||||
|
@ -4156,7 +4409,7 @@ TCB_t *pxTCB;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
|
#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
TickType_t uxTaskResetEventItemValue( void )
|
TickType_t uxTaskResetEventItemValue( void )
|
||||||
|
@ -4240,7 +4493,7 @@ TickType_t uxReturn;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
|
pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -4315,7 +4568,7 @@ TickType_t uxReturn;
|
||||||
blocked state (because a notification was already pending) or the
|
blocked state (because a notification was already pending) or the
|
||||||
task unblocked because of a notification. Otherwise the task
|
task unblocked because of a notification. Otherwise the task
|
||||||
unblocked because of a timeout. */
|
unblocked because of a timeout. */
|
||||||
if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
|
if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
|
||||||
{
|
{
|
||||||
/* A notification was not received. */
|
/* A notification was not received. */
|
||||||
xReturn = pdFALSE;
|
xReturn = pdFALSE;
|
||||||
|
@ -4800,8 +5053,24 @@ const TickType_t xConstTickCount = xTickCount;
|
||||||
#endif /* INCLUDE_vTaskSuspend */
|
#endif /* INCLUDE_vTaskSuspend */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Code below here allows additional code to be inserted into this source file,
|
||||||
|
especially where access to file scope functions and data is needed (for example
|
||||||
|
when performing module tests). */
|
||||||
|
|
||||||
#ifdef FREERTOS_MODULE_TEST
|
#ifdef FREERTOS_MODULE_TEST
|
||||||
#include "tasks_test_access_functions.h"
|
#include "tasks_test_access_functions.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 )
|
||||||
|
|
||||||
|
#include "freertos_tasks_c_additions.h"
|
||||||
|
|
||||||
|
static void freertos_tasks_c_additions_init( void )
|
||||||
|
{
|
||||||
|
#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
|
||||||
|
FREERTOS_TASKS_C_ADDITIONS_INIT();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
|
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
|
||||||
All rights reserved
|
All rights reserved
|
||||||
|
|
||||||
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
|
||||||
|
@ -100,6 +100,12 @@ configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
|
||||||
/* Misc definitions. */
|
/* Misc definitions. */
|
||||||
#define tmrNO_DELAY ( TickType_t ) 0U
|
#define tmrNO_DELAY ( TickType_t ) 0U
|
||||||
|
|
||||||
|
/* The name assigned to the timer service task. This can be overridden by
|
||||||
|
defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
|
||||||
|
#ifndef configTIMER_SERVICE_TASK_NAME
|
||||||
|
#define configTIMER_SERVICE_TASK_NAME "Tmr Svc"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The definition of the timers themselves. */
|
/* The definition of the timers themselves. */
|
||||||
typedef struct tmrTimerControl
|
typedef struct tmrTimerControl
|
||||||
{
|
{
|
||||||
|
@ -158,8 +164,8 @@ typedef struct tmrTimerQueueMessage
|
||||||
} u;
|
} u;
|
||||||
} DaemonTaskMessage_t;
|
} DaemonTaskMessage_t;
|
||||||
|
|
||||||
/*lint -e956 A manual analysis and inspection has been used to determine which
|
/*lint -save -e956 A manual analysis and inspection has been used to determine
|
||||||
static variables must be declared volatile. */
|
which static variables must be declared volatile. */
|
||||||
|
|
||||||
/* The list in which active timers are stored. Timers are referenced in expire
|
/* The list in which active timers are stored. Timers are referenced in expire
|
||||||
time order, with the nearest expiry time at the front of the list. Only the
|
time order, with the nearest expiry time at the front of the list. Only the
|
||||||
|
@ -173,7 +179,7 @@ PRIVILEGED_DATA static List_t *pxOverflowTimerList;
|
||||||
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
|
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
|
||||||
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
|
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
|
||||||
|
|
||||||
/*lint +e956 */
|
/*lint -restore */
|
||||||
|
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
@ -248,12 +254,12 @@ static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseTy
|
||||||
* Called after a Timer_t structure has been allocated either statically or
|
* Called after a Timer_t structure has been allocated either statically or
|
||||||
* dynamically to fill in the structure's members.
|
* dynamically to fill in the structure's members.
|
||||||
*/
|
*/
|
||||||
static void prvInitialiseNewTimer( const char * const pcTimerName,
|
static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const TickType_t xTimerPeriodInTicks,
|
const TickType_t xTimerPeriodInTicks,
|
||||||
const UBaseType_t uxAutoReload,
|
const UBaseType_t uxAutoReload,
|
||||||
void * const pvTimerID,
|
void * const pvTimerID,
|
||||||
TimerCallbackFunction_t pxCallbackFunction,
|
TimerCallbackFunction_t pxCallbackFunction,
|
||||||
Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION;
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
BaseType_t xTimerCreateTimerTask( void )
|
BaseType_t xTimerCreateTimerTask( void )
|
||||||
|
@ -276,7 +282,7 @@ BaseType_t xReturn = pdFAIL;
|
||||||
|
|
||||||
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
|
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
|
||||||
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
|
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
|
||||||
"Tmr Svc",
|
configTIMER_SERVICE_TASK_NAME,
|
||||||
ulTimerTaskStackSize,
|
ulTimerTaskStackSize,
|
||||||
NULL,
|
NULL,
|
||||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||||
|
@ -291,7 +297,7 @@ BaseType_t xReturn = pdFAIL;
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
xReturn = xTaskCreate( prvTimerTask,
|
xReturn = xTaskCreate( prvTimerTask,
|
||||||
"Tmr Svc",
|
configTIMER_SERVICE_TASK_NAME,
|
||||||
configTIMER_TASK_STACK_DEPTH,
|
configTIMER_TASK_STACK_DEPTH,
|
||||||
NULL,
|
NULL,
|
||||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||||
|
@ -311,11 +317,11 @@ BaseType_t xReturn = pdFAIL;
|
||||||
|
|
||||||
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
TimerHandle_t xTimerCreate( const char * const pcTimerName,
|
TimerHandle_t xTimerCreate( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const TickType_t xTimerPeriodInTicks,
|
const TickType_t xTimerPeriodInTicks,
|
||||||
const UBaseType_t uxAutoReload,
|
const UBaseType_t uxAutoReload,
|
||||||
void * const pvTimerID,
|
void * const pvTimerID,
|
||||||
TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
TimerCallbackFunction_t pxCallbackFunction )
|
||||||
{
|
{
|
||||||
Timer_t *pxNewTimer;
|
Timer_t *pxNewTimer;
|
||||||
|
|
||||||
|
@ -343,12 +349,12 @@ BaseType_t xReturn = pdFAIL;
|
||||||
|
|
||||||
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||||
|
|
||||||
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName,
|
TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const TickType_t xTimerPeriodInTicks,
|
const TickType_t xTimerPeriodInTicks,
|
||||||
const UBaseType_t uxAutoReload,
|
const UBaseType_t uxAutoReload,
|
||||||
void * const pvTimerID,
|
void * const pvTimerID,
|
||||||
TimerCallbackFunction_t pxCallbackFunction,
|
TimerCallbackFunction_t pxCallbackFunction,
|
||||||
StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
StaticTimer_t *pxTimerBuffer )
|
||||||
{
|
{
|
||||||
Timer_t *pxNewTimer;
|
Timer_t *pxNewTimer;
|
||||||
|
|
||||||
|
@ -356,7 +362,7 @@ BaseType_t xReturn = pdFAIL;
|
||||||
{
|
{
|
||||||
/* Sanity check that the size of the structure used to declare a
|
/* Sanity check that the size of the structure used to declare a
|
||||||
variable of type StaticTimer_t equals the size of the real timer
|
variable of type StaticTimer_t equals the size of the real timer
|
||||||
structures. */
|
structure. */
|
||||||
volatile size_t xSize = sizeof( StaticTimer_t );
|
volatile size_t xSize = sizeof( StaticTimer_t );
|
||||||
configASSERT( xSize == sizeof( Timer_t ) );
|
configASSERT( xSize == sizeof( Timer_t ) );
|
||||||
}
|
}
|
||||||
|
@ -385,12 +391,12 @@ BaseType_t xReturn = pdFAIL;
|
||||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||||
/*-----------------------------------------------------------*/
|
/*-----------------------------------------------------------*/
|
||||||
|
|
||||||
static void prvInitialiseNewTimer( const char * const pcTimerName,
|
static void prvInitialiseNewTimer( const char * const pcTimerName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||||
const TickType_t xTimerPeriodInTicks,
|
const TickType_t xTimerPeriodInTicks,
|
||||||
const UBaseType_t uxAutoReload,
|
const UBaseType_t uxAutoReload,
|
||||||
void * const pvTimerID,
|
void * const pvTimerID,
|
||||||
TimerCallbackFunction_t pxCallbackFunction,
|
TimerCallbackFunction_t pxCallbackFunction,
|
||||||
Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
Timer_t *pxNewTimer )
|
||||||
{
|
{
|
||||||
/* 0 is not a valid value for xTimerPeriodInTicks. */
|
/* 0 is not a valid value for xTimerPeriodInTicks. */
|
||||||
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
||||||
|
@ -760,7 +766,7 @@ TickType_t xTimeNow;
|
||||||
software timer. */
|
software timer. */
|
||||||
pxTimer = xMessage.u.xTimerParameters.pxTimer;
|
pxTimer = xMessage.u.xTimerParameters.pxTimer;
|
||||||
|
|
||||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */
|
||||||
{
|
{
|
||||||
/* The timer is in a list, remove it. */
|
/* The timer is in a list, remove it. */
|
||||||
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
|
( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
|
||||||
|
@ -945,10 +951,10 @@ static void prvCheckForValidListAndQueue( void )
|
||||||
{
|
{
|
||||||
/* The timer queue is allocated statically in case
|
/* The timer queue is allocated statically in case
|
||||||
configSUPPORT_DYNAMIC_ALLOCATION is 0. */
|
configSUPPORT_DYNAMIC_ALLOCATION is 0. */
|
||||||
static StaticQueue_t xStaticTimerQueue;
|
static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
|
||||||
static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ];
|
static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
|
||||||
|
|
||||||
xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
|
xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
|
@ -991,7 +997,7 @@ Timer_t *pxTimer = ( Timer_t * ) xTimer;
|
||||||
/* Checking to see if it is in the NULL list in effect checks to see if
|
/* Checking to see if it is in the NULL list in effect checks to see if
|
||||||
it is referenced from either the current or the overflow timer lists in
|
it is referenced from either the current or the overflow timer lists in
|
||||||
one go, but the logic has to be reversed, hence the '!'. */
|
one go, but the logic has to be reversed, hence the '!'. */
|
||||||
xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
|
xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); /*lint !e961. Cast is only redundant when NULL is passed into the macro. */
|
||||||
}
|
}
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
|
|
||||||
|
|
|
@ -78,8 +78,8 @@ Current status is alpha quality, actively developed. AP STATION mode (ie wifi cl
|
||||||
## Open Source Components
|
## Open Source Components
|
||||||
|
|
||||||
* [FreeRTOS](http://www.freertos.org/) V9.0.0
|
* [FreeRTOS](http://www.freertos.org/) V9.0.0
|
||||||
* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v1.4.1, modified via the [esp-lwip project](https://github.com/kadamski/esp-lwip) by @kadamski.
|
* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v2.0.3, with [some modifications](https://github.com/ourairquality/lwip/).
|
||||||
* [newlib](https://github.com/projectgus/newlib-xtensa) v2.2.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
|
* [newlib](https://github.com/ourairquality/newlib) v2.5.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
|
||||||
|
|
||||||
For details of how third party libraries are integrated, [see the wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries).
|
For details of how third party libraries are integrated, [see the wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries).
|
||||||
|
|
||||||
|
|
|
@ -214,8 +214,8 @@ void IRAM sdk_user_start(void) {
|
||||||
memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st));
|
memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st));
|
||||||
|
|
||||||
// By default, put the sysparam region just below the config sectors at the
|
// By default, put the sysparam region just below the config sectors at the
|
||||||
// top of the flash space
|
// top of the flash space, and allowing one extra sector spare.
|
||||||
sysparam_addr = flash_size - (4 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
|
sysparam_addr = flash_size - (5 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
|
||||||
status = sysparam_init(sysparam_addr, flash_size);
|
status = sysparam_init(sysparam_addr, flash_size);
|
||||||
if (status == SYSPARAM_NOTFOUND) {
|
if (status == SYSPARAM_NOTFOUND) {
|
||||||
status = sysparam_create_area(sysparam_addr, DEFAULT_SYSPARAM_SECTORS, false);
|
status = sysparam_create_area(sysparam_addr, DEFAULT_SYSPARAM_SECTORS, false);
|
||||||
|
@ -311,8 +311,8 @@ static void init_g_ic(void) {
|
||||||
if (sdk_g_ic.s._unknown310 > 4) {
|
if (sdk_g_ic.s._unknown310 > 4) {
|
||||||
sdk_g_ic.s._unknown310 = 4;
|
sdk_g_ic.s._unknown310 = 4;
|
||||||
}
|
}
|
||||||
if (sdk_g_ic.s._unknown1e4._unknown1e4 == 0xffffffff) {
|
if (sdk_g_ic.s.sta_ssid.ssid_length == 0xffffffff) {
|
||||||
bzero(&sdk_g_ic.s._unknown1e4, sizeof(sdk_g_ic.s._unknown1e4));
|
bzero(&sdk_g_ic.s.sta_ssid, sizeof(sdk_g_ic.s.sta_ssid));
|
||||||
bzero(&sdk_g_ic.s.sta_password, sizeof(sdk_g_ic.s.sta_password));
|
bzero(&sdk_g_ic.s.sta_password, sizeof(sdk_g_ic.s.sta_password));
|
||||||
}
|
}
|
||||||
sdk_g_ic.s.wifi_led_enable = 0;
|
sdk_g_ic.s.wifi_led_enable = 0;
|
||||||
|
|
|
@ -58,17 +58,17 @@ void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep)
|
||||||
|
|
||||||
static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 };
|
static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 };
|
||||||
|
|
||||||
void __attribute__((weak)) IRAM gpio_interrupt_handler(void)
|
void __attribute__((weak)) IRAM gpio_interrupt_handler(void *arg)
|
||||||
{
|
{
|
||||||
uint32_t status_reg = GPIO.STATUS;
|
uint32_t status_reg = GPIO.STATUS;
|
||||||
GPIO.STATUS_CLEAR = status_reg;
|
GPIO.STATUS_CLEAR = status_reg;
|
||||||
|
|
||||||
uint8_t gpio_idx;
|
uint8_t gpio_idx;
|
||||||
while((gpio_idx = __builtin_ffs(status_reg)))
|
while ((gpio_idx = __builtin_ffs(status_reg)))
|
||||||
{
|
{
|
||||||
gpio_idx--;
|
gpio_idx--;
|
||||||
status_reg &= ~BIT(gpio_idx);
|
status_reg &= ~BIT(gpio_idx);
|
||||||
if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) {
|
if (FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) {
|
||||||
gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx];
|
gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx];
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(gpio_idx);
|
handler(gpio_idx);
|
||||||
|
@ -82,8 +82,8 @@ void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, g
|
||||||
gpio_interrupt_handlers[gpio_num] = handler;
|
gpio_interrupt_handlers[gpio_num] = handler;
|
||||||
|
|
||||||
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
|
GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
|
||||||
if(int_type != GPIO_INTTYPE_NONE) {
|
if (int_type != GPIO_INTTYPE_NONE) {
|
||||||
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
|
_xt_isr_attach(INUM_GPIO, gpio_interrupt_handler, NULL);
|
||||||
_xt_isr_unmask(1<<INUM_GPIO);
|
_xt_isr_unmask(1<<INUM_GPIO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,13 +7,19 @@
|
||||||
*/
|
*/
|
||||||
#include <esp/interrupts.h>
|
#include <esp/interrupts.h>
|
||||||
|
|
||||||
_xt_isr isr[16];
|
typedef struct _xt_isr_entry_ {
|
||||||
|
_xt_isr handler;
|
||||||
|
void *arg;
|
||||||
|
} _xt_isr_entry;
|
||||||
|
|
||||||
|
_xt_isr_entry isr[16];
|
||||||
|
|
||||||
bool esp_in_isr;
|
bool esp_in_isr;
|
||||||
|
|
||||||
void IRAM _xt_isr_attach(uint8_t i, _xt_isr func)
|
void IRAM _xt_isr_attach(uint8_t i, _xt_isr func, void *arg)
|
||||||
{
|
{
|
||||||
isr[i] = func;
|
isr[i].handler = func;
|
||||||
|
isr[i].arg = arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Generic ISR handler.
|
/* Generic ISR handler.
|
||||||
|
@ -25,17 +31,20 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset)
|
||||||
esp_in_isr = true;
|
esp_in_isr = true;
|
||||||
|
|
||||||
/* WDT has highest priority (occasional WDT resets otherwise) */
|
/* WDT has highest priority (occasional WDT resets otherwise) */
|
||||||
if(intset & BIT(INUM_WDT)) {
|
if (intset & BIT(INUM_WDT)) {
|
||||||
_xt_clear_ints(BIT(INUM_WDT));
|
_xt_clear_ints(BIT(INUM_WDT));
|
||||||
isr[INUM_WDT]();
|
isr[INUM_WDT].handler(NULL);
|
||||||
intset -= BIT(INUM_WDT);
|
intset -= BIT(INUM_WDT);
|
||||||
}
|
}
|
||||||
|
|
||||||
while(intset) {
|
while (intset) {
|
||||||
uint8_t index = __builtin_ffs(intset) - 1;
|
uint8_t index = __builtin_ffs(intset) - 1;
|
||||||
uint16_t mask = BIT(index);
|
uint16_t mask = BIT(index);
|
||||||
_xt_clear_ints(mask);
|
_xt_clear_ints(mask);
|
||||||
isr[index]();
|
_xt_isr handler = isr[index].handler;
|
||||||
|
if (handler) {
|
||||||
|
handler(isr[index].arg);
|
||||||
|
}
|
||||||
intset -= mask;
|
intset -= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,7 +150,7 @@ typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num);
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
* void IRAM gpio_interrupt_handler(void) {
|
* void IRAM gpio_interrupt_handler(void *arg) {
|
||||||
* // check GPIO.STATUS
|
* // check GPIO.STATUS
|
||||||
* // write GPIO.STATUS_CLEAR
|
* // write GPIO.STATUS_CLEAR
|
||||||
* // Do something when GPIO changes
|
* // Do something when GPIO changes
|
||||||
|
|
|
@ -35,19 +35,37 @@ typedef enum {
|
||||||
INUM_TIMER_FRC2 = 10,
|
INUM_TIMER_FRC2 = 10,
|
||||||
} xt_isr_num_t;
|
} xt_isr_num_t;
|
||||||
|
|
||||||
void sdk__xt_int_exit (void);
|
void sdk__xt_int_exit(void);
|
||||||
void _xt_user_exit (void);
|
void _xt_user_exit(void);
|
||||||
void sdk__xt_tick_timer_init (void);
|
void sdk__xt_tick_timer_init(void);
|
||||||
void sdk__xt_timer_int(void);
|
void sdk__xt_timer_int(void *);
|
||||||
void sdk__xt_timer_int1(void);
|
void sdk__xt_timer_int1(void);
|
||||||
|
|
||||||
|
/* The normal running level is 0.
|
||||||
|
* The system tick isr, timer frc2_isr, sv_isr etc run at level 1.
|
||||||
|
* Debug exceptions run at level 2?
|
||||||
|
* The wdev nmi runs at level 3.
|
||||||
|
*/
|
||||||
static inline uint32_t _xt_get_intlevel(void)
|
static inline uint32_t _xt_get_intlevel(void)
|
||||||
{
|
{
|
||||||
uint32_t level;
|
uint32_t level;
|
||||||
__asm__ volatile("rsr %0, intlevel" : "=a"(level));
|
__asm__ volatile("rsr %0, ps" : "=a"(level));
|
||||||
return level;
|
return level & 0xf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are conflicting definitions for XCHAL_EXCM_LEVEL. Newlib
|
||||||
|
* defines it to be 1 and xtensa_rtos.h defines it to be 3. Don't want
|
||||||
|
* 3 as that is for the NMI and might want to check that the OS apis
|
||||||
|
* are not entered in level 3. Setting the interrupt level to 3 does
|
||||||
|
* not disable the NMI anyway. So set the level to 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef XCHAL_EXCM_LEVEL
|
||||||
|
#undef XCHAL_EXCM_LEVEL
|
||||||
|
#define XCHAL_EXCM_LEVEL 2
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Disable interrupts and return the old ps value, to pass into
|
/* Disable interrupts and return the old ps value, to pass into
|
||||||
_xt_restore_interrupts later.
|
_xt_restore_interrupts later.
|
||||||
|
|
||||||
|
@ -68,25 +86,27 @@ static inline void _xt_restore_interrupts(uint32_t new_ps)
|
||||||
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
|
__asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ESPTODO: the mask/unmask functions aren't thread safe */
|
static inline uint32_t _xt_isr_unmask(uint32_t unmask)
|
||||||
|
|
||||||
static inline void _xt_isr_unmask(uint32_t unmask)
|
|
||||||
{
|
{
|
||||||
|
uint32_t old_level = _xt_disable_interrupts();
|
||||||
uint32_t intenable;
|
uint32_t intenable;
|
||||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||||
intenable |= unmask;
|
asm volatile ("wsr %0, intenable;" :: "a" (intenable | unmask));
|
||||||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
_xt_restore_interrupts(old_level);
|
||||||
|
return intenable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void _xt_isr_mask (uint32_t mask)
|
static inline uint32_t _xt_isr_mask(uint32_t mask)
|
||||||
{
|
{
|
||||||
|
uint32_t old_level = _xt_disable_interrupts();
|
||||||
uint32_t intenable;
|
uint32_t intenable;
|
||||||
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
asm volatile ("rsr %0, intenable" : "=a" (intenable));
|
||||||
intenable &= ~mask;
|
asm volatile ("wsr %0, intenable;" :: "a" (intenable & ~mask));
|
||||||
asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
|
_xt_restore_interrupts(old_level);
|
||||||
|
return intenable;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint32_t _xt_read_ints (void)
|
static inline uint32_t _xt_read_ints(void)
|
||||||
{
|
{
|
||||||
uint32_t interrupt;
|
uint32_t interrupt;
|
||||||
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
|
asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
|
||||||
|
@ -98,9 +118,7 @@ static inline void _xt_clear_ints(uint32_t mask)
|
||||||
asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
|
asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (* _xt_isr)(void);
|
typedef void (* _xt_isr)(void *arg);
|
||||||
/* This function is implemeneted in FreeRTOS port.c at the moment,
|
void _xt_isr_attach (uint8_t i, _xt_isr func, void *arg);
|
||||||
should be moved or converted to an inline */
|
|
||||||
void _xt_isr_attach (uint8_t i, _xt_isr func);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,25 +14,25 @@
|
||||||
// 'info' is declared in app_main.o at .bss+0x4
|
// 'info' is declared in app_main.o at .bss+0x4
|
||||||
|
|
||||||
struct sdk_info_st {
|
struct sdk_info_st {
|
||||||
ip_addr_t softap_ipaddr; // 0x00
|
ip4_addr_t softap_ipaddr; // 0x00
|
||||||
ip_addr_t softap_netmask; // 0x04
|
ip4_addr_t softap_netmask; // 0x04
|
||||||
ip_addr_t softap_gw; // 0x08
|
ip4_addr_t softap_gw; // 0x08
|
||||||
ip_addr_t sta_ipaddr; // 0x0c
|
ip4_addr_t sta_ipaddr; // 0x0c
|
||||||
ip_addr_t sta_netmask; // 0x10
|
ip4_addr_t sta_netmask; // 0x10
|
||||||
ip_addr_t sta_gw; // 0x14
|
ip4_addr_t sta_gw; // 0x14
|
||||||
uint8_t softap_mac_addr[6]; // 0x18
|
uint8_t softap_mac_addr[6]; // 0x18
|
||||||
uint8_t sta_mac_addr[6]; // 0x1e
|
uint8_t sta_mac_addr[6]; // 0x1e
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct _unknown_info1 {
|
struct wl_channel {
|
||||||
uint8_t _unknown00;
|
uint8_t _unknown00;
|
||||||
uint8_t _unknown01;
|
uint8_t _unknown01;
|
||||||
uint8_t _unknown02;
|
uint8_t _unknown02;
|
||||||
uint8_t _unknown03;
|
uint8_t _unknown03;
|
||||||
uint8_t _unknown04;
|
uint8_t _unknown04;
|
||||||
uint8_t _unknown05;
|
uint8_t _unknown05;
|
||||||
uint8_t channel; // eagle_auth_done
|
uint8_t num; // eagle_auth_done
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ struct _unknown_wpa1 {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct sdk_netif_conninfo {
|
struct sdk_cnx_node {
|
||||||
uint8_t mac_addr[6];
|
uint8_t mac_addr[6];
|
||||||
uint8_t _unknown07[2];
|
uint8_t _unknown07[2];
|
||||||
|
|
||||||
|
@ -98,17 +98,19 @@ struct sdk_netif_conninfo {
|
||||||
|
|
||||||
uint32_t _unknown1c[23];
|
uint32_t _unknown1c[23];
|
||||||
|
|
||||||
struct _unknown_info1 *_unknown78; // eagle_auth_done
|
struct wl_channel *channel; // 0x78 eagle_auth_done
|
||||||
|
|
||||||
uint32_t _unknown7c[8];
|
uint32_t _unknown7c[8];
|
||||||
|
|
||||||
uint16_t _unknown9c; // ieee80211_hostap. increases by one one each timer func called.
|
uint16_t _unknown9c; // ieee80211_hostap. increases by one one each timer func called.
|
||||||
uint16_t _unknown9e;
|
uint16_t _unknown9e;
|
||||||
|
|
||||||
uint32_t _unknowna0[18];
|
uint32_t _unknowna0[17];
|
||||||
|
|
||||||
int8_t _unknowne8; //
|
void *_unknowne4;
|
||||||
int8_t _unknowne9; // ppInstallKey
|
|
||||||
|
uint8_t _unknowne8; //
|
||||||
|
uint8_t _unknowne9; // ppInstallKey
|
||||||
int8_t _unknownea;
|
int8_t _unknownea;
|
||||||
int8_t _unknowneb;
|
int8_t _unknowneb;
|
||||||
|
|
||||||
|
@ -128,9 +130,9 @@ struct sdk_g_ic_netif_info {
|
||||||
uint32_t _unknown48; // 0x48
|
uint32_t _unknown48; // 0x48
|
||||||
uint8_t _unknown4c; // 0x4c
|
uint8_t _unknown4c; // 0x4c
|
||||||
uint8_t _unknown4d[59]; // 0x4d - 0x88
|
uint8_t _unknown4d[59]; // 0x4d - 0x88
|
||||||
struct sdk_netif_conninfo *_unknown88; // 0x88
|
struct sdk_cnx_node *_unknown88; // 0x88
|
||||||
uint32_t _unknown8c; // 0x8c
|
uint32_t _unknown8c; // 0x8c
|
||||||
struct sdk_netif_conninfo *conninfo[6]; // 0x90 - 0xa8
|
struct sdk_cnx_node *cnx_nodes[6]; // 0x90 - 0xa8
|
||||||
uint8_t _unknowna8[12]; // 0xa8 - 0xb4
|
uint8_t _unknowna8[12]; // 0xa8 - 0xb4
|
||||||
struct _unknown_softap1 *_unknownb4;
|
struct _unknown_softap1 *_unknownb4;
|
||||||
uint8_t statusb8; // 0xb8 (arg of sta_status_set)
|
uint8_t statusb8; // 0xb8 (arg of sta_status_set)
|
||||||
|
@ -206,10 +208,9 @@ struct sdk_g_ic_volatile_st {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct sdk_g_ic_unk0_st {
|
struct sdk_g_ic_ssid_with_length {
|
||||||
uint16_t _unknown1e4; // sdk_wpa_config_profile
|
uint32_t ssid_length; // 0x1e4 sdk_wpa_config_profile
|
||||||
uint16_t _unknown1e6; // sdk_wpa_config_profile
|
uint8_t ssid[32]; // 0x1e8 Station ssid. Null terminated string.
|
||||||
uint8_t sta_ssid[32]; // 0x1e8 Station ssid. Null terminated string.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is the portion of g_ic which is loaded/saved to the flash ROM, and thus
|
// This is the portion of g_ic which is loaded/saved to the flash ROM, and thus
|
||||||
|
@ -224,7 +225,8 @@ struct sdk_g_ic_saved_st {
|
||||||
uint8_t wifi_led_gpio;
|
uint8_t wifi_led_gpio;
|
||||||
uint8_t wifi_led_state; // 0 or 1.
|
uint8_t wifi_led_state; // 0 or 1.
|
||||||
|
|
||||||
struct sdk_g_ic_unk0_st _unknown1e4;
|
// Current station ap config ssid and length.
|
||||||
|
struct sdk_g_ic_ssid_with_length sta_ssid; // 0x1e4
|
||||||
|
|
||||||
uint8_t _unknown208;
|
uint8_t _unknown208;
|
||||||
uint8_t _unknown209; // sdk_wpa_config_profile
|
uint8_t _unknown209; // sdk_wpa_config_profile
|
||||||
|
@ -260,7 +262,7 @@ struct sdk_g_ic_saved_st {
|
||||||
uint8_t _unknown30d; // result of ieee80211_chan2ieee
|
uint8_t _unknown30d; // result of ieee80211_chan2ieee
|
||||||
uint8_t _unknown30e;
|
uint8_t _unknown30e;
|
||||||
uint8_t _unknown30f;
|
uint8_t _unknown30f;
|
||||||
uint8_t _unknown310; // count of entries in the softap conninfo array, less two.
|
uint8_t _unknown310; // count of entries in the softap cnx_node array, less two.
|
||||||
|
|
||||||
uint8_t _unknown311[3];
|
uint8_t _unknown311[3];
|
||||||
|
|
||||||
|
@ -320,7 +322,7 @@ struct esf_buf {
|
||||||
_Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!");
|
_Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!");
|
||||||
_Static_assert(offsetof(struct sdk_info_st, sta_mac_addr) == 0x1e, "bad struct");
|
_Static_assert(offsetof(struct sdk_info_st, sta_mac_addr) == 0x1e, "bad struct");
|
||||||
|
|
||||||
_Static_assert(offsetof(struct _unknown_info1, channel) == 0x06, "bad struct");
|
_Static_assert(offsetof(struct wl_channel, num) == 0x06, "bad struct");
|
||||||
|
|
||||||
_Static_assert(sizeof(struct _unknown_softap2) == 0xcc, "_unknown_softap2 is the wrong size!");
|
_Static_assert(sizeof(struct _unknown_softap2) == 0xcc, "_unknown_softap2 is the wrong size!");
|
||||||
_Static_assert(offsetof(struct _unknown_softap2, _unknownb8) == 0xb8, "bad struct");
|
_Static_assert(offsetof(struct _unknown_softap2, _unknownb8) == 0xb8, "bad struct");
|
||||||
|
@ -331,8 +333,8 @@ _Static_assert(offsetof(struct _unknown_softap1, _unknown18) == 0x18, "bad struc
|
||||||
_Static_assert(sizeof(struct _unknown_wpa1) == 0x4c, "_unknown_wpa1 is the wrong size!");
|
_Static_assert(sizeof(struct _unknown_wpa1) == 0x4c, "_unknown_wpa1 is the wrong size!");
|
||||||
_Static_assert(offsetof(struct _unknown_wpa1, _unknown48) == 0x48, "bad struct");
|
_Static_assert(offsetof(struct _unknown_wpa1, _unknown48) == 0x48, "bad struct");
|
||||||
|
|
||||||
_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown78) == 0x78, "bad struct");
|
_Static_assert(offsetof(struct sdk_cnx_node, channel) == 0x78, "bad struct");
|
||||||
_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown108) == 0x108, "bad struct");
|
_Static_assert(offsetof(struct sdk_cnx_node, _unknown108) == 0x108, "bad struct");
|
||||||
|
|
||||||
_Static_assert(offsetof(struct sdk_g_ic_netif_info, started) == 0xbb, "bad struct");
|
_Static_assert(offsetof(struct sdk_g_ic_netif_info, started) == 0xbb, "bad struct");
|
||||||
|
|
||||||
|
@ -340,7 +342,7 @@ _Static_assert(sizeof(struct sdk_g_ic_volatile_st) == 0x1d8, "sdk_g_ic_volatile_
|
||||||
_Static_assert(offsetof(struct sdk_g_ic_volatile_st, _unknown1d5) == 0x1d5, "bad struct");
|
_Static_assert(offsetof(struct sdk_g_ic_volatile_st, _unknown1d5) == 0x1d5, "bad struct");
|
||||||
|
|
||||||
_Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!");
|
_Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!");
|
||||||
_Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown1e4) == 0x1e4 - 0x1d8, "bad struct");
|
_Static_assert(offsetof(struct sdk_g_ic_saved_st, sta_ssid) == 0x1e4 - 0x1d8, "bad struct");
|
||||||
_Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown546) == 0x546 - 0x1d8, "bad struct");
|
_Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown546) == 0x546 - 0x1d8, "bad struct");
|
||||||
|
|
||||||
_Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!");
|
_Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!");
|
||||||
|
@ -357,21 +359,16 @@ _Static_assert(offsetof(struct esf_buf, length) == 0x16, "bad struct");
|
||||||
// ieee80211_output_pbuf and perhaps elsewhere. The value is just passed through
|
// ieee80211_output_pbuf and perhaps elsewhere. The value is just passed through
|
||||||
// lwip and and not used by lwip so just ensure this slot is at the expected
|
// lwip and and not used by lwip so just ensure this slot is at the expected
|
||||||
// offset.
|
// offset.
|
||||||
_Static_assert(offsetof(struct netif, state) == 28, "netif->state offset wrong!");
|
_Static_assert(offsetof(struct netif, state) == 4, "netif->state offset wrong!");
|
||||||
|
|
||||||
// Some sdk uses of netif->hwaddr have been converted to source code, but many
|
// Some sdk uses of netif->hwaddr have been converted to source code, but many
|
||||||
// remain, but the content of this slot should not change in future versions of
|
// remain, but the content of this slot should not change in future versions of
|
||||||
// lwip, so just ensure it is at the expected offset.
|
// lwip, so just ensure it is at the expected offset. Note the sdk binary
|
||||||
_Static_assert(offsetof(struct netif, hwaddr) == 41, "netif->hwaddr offset wrong!");
|
// libraries have been patched to move this offset from 41 to 42 to keep it
|
||||||
|
// 16-bit aligned to keep lwip v2 happy.
|
||||||
|
_Static_assert(offsetof(struct netif, hwaddr) == 8, "netif->hwaddr offset wrong!");
|
||||||
|
|
||||||
// Most sdk uses of the netif->flags have been converted to source code. One
|
_Static_assert(offsetof(struct pbuf, esf_buf) == 16, "pbuf->esf_buf offset wrong!");
|
||||||
// known sdk binary read of the flags remains in wl_cnx.o:sdk_cnx_sta_leave
|
|
||||||
// which checks the NETIF_FLAG_DHCP flag. The NETIF_FLAG_DHCP has been removed
|
|
||||||
// in lwip v2, so some lwip hacks are needed to handle this for now until
|
|
||||||
// wl_cnx.o is converted so source code too.
|
|
||||||
_Static_assert(offsetof(struct netif, flags) == 47, "netif->flags offset wrong!");
|
|
||||||
|
|
||||||
_Static_assert(offsetof(struct pbuf, eb) == 16, "pbuf->eb offset wrong!");
|
|
||||||
|
|
||||||
|
|
||||||
/// Misc.
|
/// Misc.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <esp/uart.h>
|
#include <esp/uart.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdout_redirect.h>
|
#include <stdout_redirect.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
extern void *xPortSupervisorStackPointer;
|
extern void *xPortSupervisorStackPointer;
|
||||||
|
|
||||||
|
@ -135,6 +136,14 @@ int _stat_r(struct _reent *r, const char *pathname, void *buf);
|
||||||
__attribute__((weak, alias("syscall_returns_enosys")))
|
__attribute__((weak, alias("syscall_returns_enosys")))
|
||||||
off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence);
|
off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence);
|
||||||
|
|
||||||
|
__attribute__((weak, alias("_gettimeofday_r")))
|
||||||
|
int _gettimeofday_r _PARAMS ((struct _reent *r, struct timeval *now, void *p)) {
|
||||||
|
now->tv_sec = 0;
|
||||||
|
now->tv_usec = 0;
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Generic stub for any newlib syscall that fails with errno ENOSYS
|
/* Generic stub for any newlib syscall that fails with errno ENOSYS
|
||||||
("Function not implemented") and a return value equivalent to
|
("Function not implemented") and a return value equivalent to
|
||||||
(int)-1. */
|
(int)-1. */
|
||||||
|
|
|
@ -133,7 +133,7 @@ static bool IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size)
|
||||||
|
|
||||||
uint32_t offset = write_bytes_to_page;
|
uint32_t offset = write_bytes_to_page;
|
||||||
uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
|
uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
|
||||||
for (uint8_t i = 0; i != pages_to_write; i++) {
|
for (uint32_t i = 0; i < pages_to_write; i++) {
|
||||||
if (!spi_write_page(&sdk_flashchip, addr + offset,
|
if (!spi_write_page(&sdk_flashchip, addr + offset,
|
||||||
dst + offset, sdk_flashchip.page_size)) {
|
dst + offset, sdk_flashchip.page_size)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -801,9 +801,13 @@ sysparam_status_t sysparam_get_bool(const char *key, bool *result) {
|
||||||
do {
|
do {
|
||||||
if (binary) {
|
if (binary) {
|
||||||
if (data_len == 1) { // int8 value
|
if (data_len == 1) { // int8 value
|
||||||
*result = (int8_t)(*buf) ? true : false;
|
uint8_t value;
|
||||||
|
memcpy(&value, buf, sizeof(value));
|
||||||
|
*result = value ? true : false;
|
||||||
} else if (data_len == 4) { // int32 value
|
} else if (data_len == 4) { // int32 value
|
||||||
*result = (int32_t)(*buf) ? true : false;
|
uint32_t value;
|
||||||
|
memcpy(&value, buf, sizeof(value));
|
||||||
|
*result = value ? true : false;
|
||||||
} else {
|
} else {
|
||||||
status = SYSPARAM_PARSEFAILED;
|
status = SYSPARAM_PARSEFAILED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/* Very basic example showing usage of access point mode and the DHCP server.
|
/**
|
||||||
|
* Very basic example showing usage of access point mode and the DHCP server.
|
||||||
The ESP in the example runs a telnet server on 172.16.0.1 (port 23) that
|
* The ESP in the example runs a telnet server on 172.16.0.1 (port 23) that
|
||||||
outputs some status information if you connect to it, then closes
|
* outputs some status information if you connect to it, then closes
|
||||||
the connection.
|
* the connection.
|
||||||
|
*
|
||||||
This example code is in the public domain.
|
* This example code is in the public domain.
|
||||||
*/
|
*/
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <espressif/esp_common.h>
|
#include <espressif/esp_common.h>
|
||||||
|
@ -36,62 +36,55 @@ void user_init(void)
|
||||||
IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0);
|
IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0);
|
||||||
sdk_wifi_set_ip_info(1, &ap_ip);
|
sdk_wifi_set_ip_info(1, &ap_ip);
|
||||||
|
|
||||||
struct sdk_softap_config ap_config = {
|
struct sdk_softap_config ap_config = { .ssid = AP_SSID, .ssid_hidden = 0, .channel = 3, .ssid_len = strlen(AP_SSID), .authmode =
|
||||||
.ssid = AP_SSID,
|
AUTH_WPA_WPA2_PSK, .password = AP_PSK, .max_connection = 3, .beacon_interval = 100, };
|
||||||
.ssid_hidden = 0,
|
|
||||||
.channel = 3,
|
|
||||||
.ssid_len = strlen(AP_SSID),
|
|
||||||
.authmode = AUTH_WPA_WPA2_PSK,
|
|
||||||
.password = AP_PSK,
|
|
||||||
.max_connection = 3,
|
|
||||||
.beacon_interval = 100,
|
|
||||||
};
|
|
||||||
sdk_wifi_softap_set_config(&ap_config);
|
sdk_wifi_softap_set_config(&ap_config);
|
||||||
|
|
||||||
ip_addr_t first_client_ip;
|
|
||||||
IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
|
|
||||||
dhcpserver_start(&first_client_ip, 4);
|
|
||||||
|
|
||||||
xTaskCreate(telnetTask, "telnetTask", 512, NULL, 2, NULL);
|
xTaskCreate(telnetTask, "telnetTask", 512, NULL, 2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Telnet task listens on port 23, returns some status information and then closes
|
/* Telnet task listens on port 23, returns some status information and then closes
|
||||||
the connection if you connect to it.
|
the connection if you connect to it.
|
||||||
*/
|
*/
|
||||||
static void telnetTask(void *pvParameters)
|
static void telnetTask(void *pvParameters)
|
||||||
{
|
{
|
||||||
struct netconn *nc = netconn_new (NETCONN_TCP);
|
ip_addr_t first_client_ip;
|
||||||
if(!nc) {
|
IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
|
||||||
printf("Status monitor: Failed to allocate socket.\r\n");
|
dhcpserver_start(&first_client_ip, 4);
|
||||||
return;
|
|
||||||
}
|
|
||||||
netconn_bind(nc, IP_ADDR_ANY, TELNET_PORT);
|
|
||||||
netconn_listen(nc);
|
|
||||||
|
|
||||||
while(1) {
|
struct netconn *nc = netconn_new(NETCONN_TCP);
|
||||||
struct netconn *client = NULL;
|
if (!nc)
|
||||||
err_t err = netconn_accept(nc, &client);
|
{
|
||||||
|
printf("Status monitor: Failed to allocate socket.\r\n");
|
||||||
if ( err != ERR_OK ) {
|
return;
|
||||||
if(client)
|
|
||||||
netconn_delete(client);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
netconn_bind(nc, IP_ANY_TYPE, TELNET_PORT);
|
||||||
|
netconn_listen(nc);
|
||||||
|
|
||||||
ip_addr_t client_addr;
|
while (1)
|
||||||
uint16_t port_ignore;
|
{
|
||||||
netconn_peer(client, &client_addr, &port_ignore);
|
struct netconn *client = NULL;
|
||||||
|
err_t err = netconn_accept(nc, &client);
|
||||||
|
|
||||||
char buf[80];
|
if (err != ERR_OK)
|
||||||
snprintf(buf, sizeof(buf), "Uptime %d seconds\r\n",
|
{
|
||||||
xTaskGetTickCount()*portTICK_PERIOD_MS/1000);
|
if (client)
|
||||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
netconn_delete(client);
|
||||||
snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize());
|
continue;
|
||||||
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),
|
ip_addr_t client_addr;
|
||||||
ip4_addr3(&client_addr), ip4_addr4(&client_addr));
|
uint16_t port_ignore;
|
||||||
netconn_write(client, buf, strlen(buf), NETCONN_COPY);
|
netconn_peer(client, &client_addr, &port_ignore);
|
||||||
netconn_delete(client);
|
|
||||||
}
|
char buf[80];
|
||||||
|
snprintf(buf, sizeof(buf), "Uptime %d seconds\r\n", xTaskGetTickCount() * portTICK_PERIOD_MS / 1000);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,13 +17,13 @@ const int freq_frc2 = 10;
|
||||||
static volatile uint32_t frc1_count;
|
static volatile uint32_t frc1_count;
|
||||||
static volatile uint32_t frc2_count;
|
static volatile uint32_t frc2_count;
|
||||||
|
|
||||||
void frc1_interrupt_handler(void)
|
void frc1_interrupt_handler(void *arg)
|
||||||
{
|
{
|
||||||
frc1_count++;
|
frc1_count++;
|
||||||
gpio_toggle(gpio_frc1);
|
gpio_toggle(gpio_frc1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void frc2_interrupt_handler(void)
|
void frc2_interrupt_handler(void *arg)
|
||||||
{
|
{
|
||||||
/* FRC2 needs the match register updated on each timer interrupt */
|
/* FRC2 needs the match register updated on each timer interrupt */
|
||||||
timer_set_frequency(FRC2, freq_frc2);
|
timer_set_frequency(FRC2, freq_frc2);
|
||||||
|
@ -47,8 +47,8 @@ void user_init(void)
|
||||||
timer_set_run(FRC2, false);
|
timer_set_run(FRC2, false);
|
||||||
|
|
||||||
/* set up ISRs */
|
/* set up ISRs */
|
||||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
|
||||||
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler);
|
_xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler, NULL);
|
||||||
|
|
||||||
/* configure timer frequencies */
|
/* configure timer frequencies */
|
||||||
timer_set_frequency(FRC1, freq_frc1);
|
timer_set_frequency(FRC1, freq_frc1);
|
||||||
|
|
|
@ -97,7 +97,7 @@ void timerRegTask(void *pvParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IRAM void frc1_handler(void)
|
IRAM void frc1_handler(void *arg)
|
||||||
{
|
{
|
||||||
frc1_handler_call_count++;
|
frc1_handler_call_count++;
|
||||||
frc1_last_count_val = TIMER(0).COUNT;
|
frc1_last_count_val = TIMER(0).COUNT;
|
||||||
|
@ -106,7 +106,7 @@ IRAM void frc1_handler(void)
|
||||||
//TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000;
|
//TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void frc2_handler(void)
|
void frc2_handler(void *arg)
|
||||||
{
|
{
|
||||||
frc2_handler_call_count++;
|
frc2_handler_call_count++;
|
||||||
frc2_last_count_val = TIMER(1).COUNT;
|
frc2_last_count_val = TIMER(1).COUNT;
|
||||||
|
@ -127,9 +127,9 @@ void user_init(void)
|
||||||
TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256);
|
TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256);
|
||||||
|
|
||||||
DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1;
|
DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1;
|
||||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_handler);
|
_xt_isr_attach(INUM_TIMER_FRC1, frc1_handler, NULL);
|
||||||
_xt_isr_unmask(1<<INUM_TIMER_FRC1);
|
_xt_isr_unmask(1<<INUM_TIMER_FRC1);
|
||||||
_xt_isr_attach(INUM_TIMER_FRC2, frc2_handler);
|
_xt_isr_attach(INUM_TIMER_FRC2, frc2_handler, NULL);
|
||||||
_xt_isr_unmask(1<<INUM_TIMER_FRC2);
|
_xt_isr_unmask(1<<INUM_TIMER_FRC2);
|
||||||
|
|
||||||
TIMER(0).CTRL |= TIMER_CTRL_RUN;
|
TIMER(0).CTRL |= TIMER_CTRL_RUN;
|
||||||
|
|
|
@ -237,7 +237,7 @@ static volatile bool frc1_ran;
|
||||||
static volatile bool frc1_finished;
|
static volatile bool frc1_finished;
|
||||||
static volatile char frc1_buf[80];
|
static volatile char frc1_buf[80];
|
||||||
|
|
||||||
static void frc1_interrupt_handler(void)
|
static void frc1_interrupt_handler(void *arg)
|
||||||
{
|
{
|
||||||
frc1_ran = true;
|
frc1_ran = true;
|
||||||
timer_set_run(FRC1, false);
|
timer_set_run(FRC1, false);
|
||||||
|
@ -250,7 +250,7 @@ static void test_isr()
|
||||||
printf("Testing behaviour inside ISRs...\r\n");
|
printf("Testing behaviour inside ISRs...\r\n");
|
||||||
timer_set_interrupts(FRC1, false);
|
timer_set_interrupts(FRC1, false);
|
||||||
timer_set_run(FRC1, false);
|
timer_set_run(FRC1, false);
|
||||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
|
||||||
timer_set_frequency(FRC1, 1000);
|
timer_set_frequency(FRC1, 1000);
|
||||||
timer_set_interrupts(FRC1, true);
|
timer_set_interrupts(FRC1, true);
|
||||||
timer_set_run(FRC1, true);
|
timer_set_run(FRC1, true);
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
|
|
||||||
#include "ssid_config.h"
|
#include "ssid_config.h"
|
||||||
|
|
||||||
#define WEB_SERVER "chainxor.org"
|
#define WEB_SERVER "ipv6.google.com"
|
||||||
#define WEB_PORT 80
|
#define WEB_PORT 80
|
||||||
#define WEB_URL "http://chainxor.org/"
|
#define WEB_PATH "/"
|
||||||
|
|
||||||
void http_get_task(void *pvParameters)
|
void http_get_task(void *pvParameters)
|
||||||
{
|
{
|
||||||
|
@ -31,7 +31,7 @@ void http_get_task(void *pvParameters)
|
||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
const struct addrinfo hints = {
|
const struct addrinfo hints = {
|
||||||
.ai_family = AF_INET,
|
.ai_family = AF_UNSPEC,
|
||||||
.ai_socktype = SOCK_STREAM,
|
.ai_socktype = SOCK_STREAM,
|
||||||
};
|
};
|
||||||
struct addrinfo *res;
|
struct addrinfo *res;
|
||||||
|
@ -39,7 +39,7 @@ void http_get_task(void *pvParameters)
|
||||||
printf("Running DNS lookup for %s...\r\n", WEB_SERVER);
|
printf("Running DNS lookup for %s...\r\n", WEB_SERVER);
|
||||||
int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);
|
int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);
|
||||||
|
|
||||||
if(err != 0 || res == NULL) {
|
if (err != 0 || res == NULL) {
|
||||||
printf("DNS lookup failed err=%d res=%p\r\n", err, res);
|
printf("DNS lookup failed err=%d res=%p\r\n", err, res);
|
||||||
if(res)
|
if(res)
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
|
@ -47,9 +47,28 @@ void http_get_task(void *pvParameters)
|
||||||
failures++;
|
failures++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
|
|
||||||
struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
|
#if LWIP_IPV6
|
||||||
printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));
|
{
|
||||||
|
struct netif *netif = sdk_system_get_netif(0);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||||
|
printf(" ip6 %d state %x\n", i, netif_ip6_addr_state(netif, i));
|
||||||
|
if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)))
|
||||||
|
printf(" ip6 addr %d = %s\n", i, ip6addr_ntoa(netif_ip6_addr(netif, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct sockaddr *sa = res->ai_addr;
|
||||||
|
if (sa->sa_family == AF_INET) {
|
||||||
|
printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr));
|
||||||
|
}
|
||||||
|
#if LWIP_IPV6
|
||||||
|
if (sa->sa_family == AF_INET6) {
|
||||||
|
printf("DNS lookup succeeded. IP=%s\r\n", inet6_ntoa(((struct sockaddr_in6 *)sa)->sin6_addr));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int s = socket(res->ai_family, res->ai_socktype, 0);
|
int s = socket(res->ai_family, res->ai_socktype, 0);
|
||||||
if(s < 0) {
|
if(s < 0) {
|
||||||
|
@ -75,8 +94,10 @@ void http_get_task(void *pvParameters)
|
||||||
freeaddrinfo(res);
|
freeaddrinfo(res);
|
||||||
|
|
||||||
const char *req =
|
const char *req =
|
||||||
"GET "WEB_URL"\r\n"
|
"GET "WEB_PATH" HTTP/1.1\r\n"
|
||||||
|
"Host: "WEB_SERVER"\r\n"
|
||||||
"User-Agent: esp-open-rtos/0.1 esp8266\r\n"
|
"User-Agent: esp-open-rtos/0.1 esp8266\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
"\r\n";
|
"\r\n";
|
||||||
if (write(s, req, strlen(req)) < 0) {
|
if (write(s, req, strlen(req)) < 0) {
|
||||||
printf("... socket send failed\r\n");
|
printf("... socket send failed\r\n");
|
||||||
|
@ -126,6 +147,6 @@ void user_init(void)
|
||||||
sdk_wifi_set_opmode(STATION_MODE);
|
sdk_wifi_set_opmode(STATION_MODE);
|
||||||
sdk_wifi_station_set_config(&config);
|
sdk_wifi_station_set_config(&config);
|
||||||
|
|
||||||
xTaskCreate(&http_get_task, "get_task", 256, NULL, 2, NULL);
|
xTaskCreate(&http_get_task, "get_task", 384, NULL, 2, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,7 @@ static inline void init_descriptors_list()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DMA interrupt handler. It is called each time a DMA block is finished processing.
|
// DMA interrupt handler. It is called each time a DMA block is finished processing.
|
||||||
static void dma_isr_handler(void)
|
static void dma_isr_handler(void *args)
|
||||||
{
|
{
|
||||||
portBASE_TYPE task_awoken = pdFALSE;
|
portBASE_TYPE task_awoken = pdFALSE;
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ void play_task(void *pvParameters)
|
||||||
|
|
||||||
i2s_pins_t i2s_pins = {.data = true, .clock = true, .ws = true};
|
i2s_pins_t i2s_pins = {.data = true, .clock = true, .ws = true};
|
||||||
|
|
||||||
i2s_dma_init(dma_isr_handler, clock_div, i2s_pins);
|
i2s_dma_init(dma_isr_handler, NULL, clock_div, i2s_pins);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
init_descriptors_list();
|
init_descriptors_list();
|
||||||
|
|
|
@ -8,7 +8,7 @@ include ../../common.mk
|
||||||
# `make dump-flash` can be used to view the current contents of the sysparam
|
# `make dump-flash` can be used to view the current contents of the sysparam
|
||||||
# regions in flash.
|
# regions in flash.
|
||||||
dump-flash:
|
dump-flash:
|
||||||
esptool.py read_flash 0x1f8000 8192 r1.bin
|
esptool.py read_flash 0x1f7000 8192 r1.bin
|
||||||
hexdump -C r1.bin
|
hexdump -C r1.bin
|
||||||
esptool.py read_flash 0x1fa000 8192 r2.bin
|
esptool.py read_flash 0x1f9000 8192 r2.bin
|
||||||
hexdump -C r2.bin
|
hexdump -C r2.bin
|
||||||
|
|
|
@ -45,7 +45,7 @@ size_t tty_readline(char *buffer, size_t buf_size, bool echo) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
c = getchar();
|
c = getchar();
|
||||||
if (c == '\r') {
|
if (c == '\r' || c == '\n') {
|
||||||
if (echo) putchar('\n');
|
if (echo) putchar('\n');
|
||||||
break;
|
break;
|
||||||
} else if (c == '\b' || c == 0x7f) {
|
} else if (c == '\b' || c == 0x7f) {
|
||||||
|
@ -173,7 +173,7 @@ void sysparam_editor_task(void *pvParameters) {
|
||||||
// stuff, so if the user uses this utility to reformat it, it will put
|
// stuff, so if the user uses this utility to reformat it, it will put
|
||||||
// it somewhere the system will find it later
|
// it somewhere the system will find it later
|
||||||
num_sectors = DEFAULT_SYSPARAM_SECTORS;
|
num_sectors = DEFAULT_SYSPARAM_SECTORS;
|
||||||
base_addr = sdk_flashchip.chip_size - (4 + num_sectors) * sdk_flashchip.sector_size;
|
base_addr = sdk_flashchip.chip_size - (5 + num_sectors) * sdk_flashchip.sector_size;
|
||||||
}
|
}
|
||||||
while (true) {
|
while (true) {
|
||||||
printf("==> ");
|
printf("==> ");
|
||||||
|
@ -246,5 +246,7 @@ void user_init(void)
|
||||||
{
|
{
|
||||||
uart_set_baud(0, 115200);
|
uart_set_baud(0, 115200);
|
||||||
|
|
||||||
|
sdk_wifi_set_opmode(NULL_MODE);
|
||||||
|
|
||||||
xTaskCreate(sysparam_editor_task, "sysparam_editor_task", 512, NULL, 2, NULL);
|
xTaskCreate(sysparam_editor_task, "sysparam_editor_task", 512, NULL, 2, NULL);
|
||||||
}
|
}
|
||||||
|
|
5
examples/tcp_non_blocking/Makefile
Normal file
5
examples/tcp_non_blocking/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# Makefile for tcp_non_blocking example
|
||||||
|
PROGRAM=tcp_non_blocking
|
||||||
|
EXTRA_COMPONENTS=extras/dhcpserver
|
||||||
|
|
||||||
|
include ../../common.mk
|
203
examples/tcp_non_blocking/tcp_non_blocking.c
Normal file
203
examples/tcp_non_blocking/tcp_non_blocking.c
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
/*
|
||||||
|
The ESP in the example runs a echo server on 172.16.0.1 (port 50 and 100 ) that
|
||||||
|
outputs information about your ip/port then echo all text you write.
|
||||||
|
It is manage multiple connection and multiple port with one task.
|
||||||
|
|
||||||
|
This example code is in the public domain.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
#include <esp8266.h>
|
||||||
|
#include <esp/uart.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
#include <queue.h>
|
||||||
|
#include <dhcpserver.h>
|
||||||
|
#include <lwip/api.h>
|
||||||
|
|
||||||
|
#define AP_SSID "esp-open-rtos AP"
|
||||||
|
#define AP_PSK "esp-open-rtos"
|
||||||
|
#define ECHO_PORT_1 50
|
||||||
|
#define ECHO_PORT_2 100
|
||||||
|
#define EVENTS_QUEUE_SIZE 10
|
||||||
|
|
||||||
|
#ifdef CALLBACK_DEBUG
|
||||||
|
#define debug(s, ...) printf("%s: " s "\n", "Cb:", ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug(s, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QueueHandle_t xQueue_events;
|
||||||
|
typedef struct {
|
||||||
|
struct netconn *nc ;
|
||||||
|
uint8_t type ;
|
||||||
|
} netconn_events;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function will be call in Lwip in each event on netconn
|
||||||
|
*/
|
||||||
|
static void netCallback(struct netconn *conn, enum netconn_evt evt, uint16_t length)
|
||||||
|
{
|
||||||
|
//Show some callback information (debug)
|
||||||
|
debug("sock:%u\tsta:%u\tevt:%u\tlen:%u\ttyp:%u\tfla:%02X\terr:%d", \
|
||||||
|
(uint32_t)conn,conn->state,evt,length,conn->type,conn->flags,conn->last_err);
|
||||||
|
|
||||||
|
netconn_events events ;
|
||||||
|
|
||||||
|
//If netconn got error, it is close or deleted, dont do treatments on it.
|
||||||
|
if (conn->pending_err)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//Treatments only on rcv events.
|
||||||
|
switch (evt) {
|
||||||
|
case NETCONN_EVT_RCVPLUS:
|
||||||
|
events.nc = conn ;
|
||||||
|
events.type = evt ;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send the event to the queue
|
||||||
|
xQueueSend(xQueue_events, &events, 1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize a server netconn and listen port
|
||||||
|
*/
|
||||||
|
static void set_tcp_server_netconn(struct netconn **nc, uint16_t port, netconn_callback callback)
|
||||||
|
{
|
||||||
|
if(nc == NULL)
|
||||||
|
{
|
||||||
|
printf("%s: netconn missing .\n",__FUNCTION__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*nc = netconn_new_with_callback(NETCONN_TCP, netCallback);
|
||||||
|
if(!*nc) {
|
||||||
|
printf("Status monitor: Failed to allocate netconn.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
netconn_set_nonblocking(*nc,NETCONN_FLAG_NON_BLOCKING);
|
||||||
|
//netconn_set_recvtimeout(*nc, 10);
|
||||||
|
netconn_bind(*nc, IP_ADDR_ANY, port);
|
||||||
|
netconn_listen(*nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close and delete a socket properly
|
||||||
|
*/
|
||||||
|
static void close_tcp_netconn(struct netconn *nc)
|
||||||
|
{
|
||||||
|
nc->pending_err=ERR_CLSD; //It is hacky way to be sure than callback will don't do treatment on a netconn closed and deleted
|
||||||
|
netconn_close(nc);
|
||||||
|
netconn_delete(nc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This task manage each netconn connection without block anything
|
||||||
|
*/
|
||||||
|
static void nonBlockingTCP(void *pvParameters)
|
||||||
|
{
|
||||||
|
|
||||||
|
struct netconn *nc = NULL; // To create servers
|
||||||
|
|
||||||
|
set_tcp_server_netconn(&nc, ECHO_PORT_1, netCallback);
|
||||||
|
printf("Server netconn %u ready on port %u.\n",(uint32_t)nc, ECHO_PORT_1);
|
||||||
|
set_tcp_server_netconn(&nc, ECHO_PORT_2, netCallback);
|
||||||
|
printf("Server netconn %u ready on port %u.\n",(uint32_t)nc, ECHO_PORT_2);
|
||||||
|
|
||||||
|
struct netbuf *netbuf = NULL; // To store incoming Data
|
||||||
|
struct netconn *nc_in = NULL; // To accept incoming netconn
|
||||||
|
//
|
||||||
|
char buf[50];
|
||||||
|
char* buffer;
|
||||||
|
uint16_t len_buf;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
|
||||||
|
netconn_events events;
|
||||||
|
xQueueReceive(xQueue_events, &events, portMAX_DELAY); // Wait here an event on netconn
|
||||||
|
|
||||||
|
if (events.nc->state == NETCONN_LISTEN) // If netconn is a server and receive incoming event on it
|
||||||
|
{
|
||||||
|
printf("Client incoming on server %u.\n", (uint32_t)events.nc);
|
||||||
|
int err = netconn_accept(events.nc, &nc_in);
|
||||||
|
if (err != ERR_OK)
|
||||||
|
{
|
||||||
|
if(nc_in)
|
||||||
|
netconn_delete(nc_in);
|
||||||
|
}
|
||||||
|
printf("New client is %u.\n",(uint32_t)nc_in);
|
||||||
|
ip_addr_t client_addr; //Address port
|
||||||
|
uint16_t client_port; //Client port
|
||||||
|
netconn_peer(nc_in, &client_addr, &client_port);
|
||||||
|
snprintf(buf, sizeof(buf), "Your address is %d.%d.%d.%d:%u.\r\n",
|
||||||
|
ip4_addr1(&client_addr), ip4_addr2(&client_addr),
|
||||||
|
ip4_addr3(&client_addr), ip4_addr4(&client_addr),
|
||||||
|
client_port);
|
||||||
|
netconn_write(nc_in, buf, strlen(buf), NETCONN_COPY);
|
||||||
|
}
|
||||||
|
else if(events.nc->state != NETCONN_LISTEN) // If netconn is the client and receive data
|
||||||
|
{
|
||||||
|
if ((netconn_recv(events.nc, &netbuf)) == ERR_OK) // data incoming ?
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
netbuf_data(netbuf, (void*)&buffer, &len_buf);
|
||||||
|
netconn_write(events.nc, buffer, strlen(buffer), NETCONN_COPY);
|
||||||
|
printf("Client %u send: %s\n",(uint32_t)events.nc,buffer);
|
||||||
|
}
|
||||||
|
while (netbuf_next(netbuf) >= 0);
|
||||||
|
netbuf_delete(netbuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close_tcp_netconn(events.nc);
|
||||||
|
printf("Error read netconn %u, close it \n",(uint32_t)events.nc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
sdk_os_delay_us(500); // Wait UART
|
||||||
|
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||||
|
|
||||||
|
sdk_wifi_set_opmode(SOFTAP_MODE);
|
||||||
|
struct ip_info ap_ip;
|
||||||
|
IP4_ADDR(&ap_ip.ip, 172, 16, 0, 1);
|
||||||
|
IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0);
|
||||||
|
IP4_ADDR(&ap_ip.netmask, 255, 255, 0, 0);
|
||||||
|
sdk_wifi_set_ip_info(1, &ap_ip);
|
||||||
|
|
||||||
|
struct sdk_softap_config ap_config = {
|
||||||
|
.ssid = AP_SSID,
|
||||||
|
.ssid_hidden = 0,
|
||||||
|
.channel = 3,
|
||||||
|
.ssid_len = strlen(AP_SSID),
|
||||||
|
.authmode = AUTH_WPA_WPA2_PSK,
|
||||||
|
.password = AP_PSK,
|
||||||
|
.max_connection = 3,
|
||||||
|
.beacon_interval = 100,
|
||||||
|
};
|
||||||
|
sdk_wifi_softap_set_config(&ap_config);
|
||||||
|
|
||||||
|
ip_addr_t first_client_ip;
|
||||||
|
IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
|
||||||
|
dhcpserver_start(&first_client_ip, 4);
|
||||||
|
printf("DHCP started\n");
|
||||||
|
|
||||||
|
//Create a queue to store events on netconns
|
||||||
|
xQueue_events = xQueueCreate( EVENTS_QUEUE_SIZE, sizeof(netconn_events));
|
||||||
|
|
||||||
|
xTaskCreate(nonBlockingTCP, "lwiptest_noblock", 512, NULL, 2, NULL);
|
||||||
|
}
|
|
@ -94,18 +94,23 @@ static void gpiomon()
|
||||||
int i = 0;
|
int i = 0;
|
||||||
printf("\n\n\nWelcome to gpiomon. Type 'help<enter>' for, well, help\n");
|
printf("\n\n\nWelcome to gpiomon. Type 'help<enter>' for, well, help\n");
|
||||||
printf("%% ");
|
printf("%% ");
|
||||||
|
fflush(stdout); // stdout is line buffered
|
||||||
while(1) {
|
while(1) {
|
||||||
if (read(0, (void*)&ch, 1)) { // 0 is stdin
|
if (read(0, (void*)&ch, 1)) { // 0 is stdin
|
||||||
printf("%c", ch);
|
printf("%c", ch);
|
||||||
|
fflush(stdout);
|
||||||
if (ch == '\n' || ch == '\r') {
|
if (ch == '\n' || ch == '\r') {
|
||||||
cmd[i] = 0;
|
cmd[i] = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
printf("\n");
|
printf("\n");
|
||||||
handle_command((char*) cmd);
|
handle_command((char*) cmd);
|
||||||
printf("%% ");
|
printf("%% ");
|
||||||
|
fflush(stdout);
|
||||||
} else {
|
} else {
|
||||||
if (i < sizeof(cmd)) cmd[i++] = ch;
|
if (i < sizeof(cmd)) cmd[i++] = ch;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
printf("You will never see this print as read(...) is blocking\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,9 +202,8 @@ void tls_server_task(void *pvParameters)
|
||||||
socklen_t peer_addr_len = sizeof(struct sockaddr_in);
|
socklen_t peer_addr_len = sizeof(struct sockaddr_in);
|
||||||
getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
|
getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len);
|
||||||
unsigned char buf[256];
|
unsigned char buf[256];
|
||||||
int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\nFree heap size is %d bytes\n",
|
int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\nFree heap size is %d bytes\n",
|
||||||
ip4_addr1(&peer_addr.sin_addr), ip4_addr2(&peer_addr.sin_addr),
|
IP2STR((ip4_addr_t *)&peer_addr.sin_addr.s_addr),
|
||||||
ip4_addr3(&peer_addr.sin_addr), ip4_addr4(&peer_addr.sin_addr),
|
|
||||||
peer_addr.sin_port, xPortGetFreeHeapSize());
|
peer_addr.sin_port, xPortGetFreeHeapSize());
|
||||||
while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0)
|
while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -146,9 +146,8 @@ void tls_server_task(void *pvParameters)
|
||||||
|
|
||||||
/* Prepare a message to the client */
|
/* Prepare a message to the client */
|
||||||
unsigned char buf[100];
|
unsigned char buf[100];
|
||||||
int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\r\nFree heap size is %d bytes\r\n",
|
int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\r\nFree heap size is %d bytes\r\n",
|
||||||
ip4_addr1(&sa.sin_addr), ip4_addr2(&sa.sin_addr),
|
IP2STR((ip4_addr_t *)&sa.sin_addr.s_addr),
|
||||||
ip4_addr3(&sa.sin_addr), ip4_addr4(&sa.sin_addr),
|
|
||||||
ntohs(sa.sin_port), xPortGetFreeHeapSize());
|
ntohs(sa.sin_port), xPortGetFreeHeapSize());
|
||||||
|
|
||||||
/* Send the message and close the connection */
|
/* Send the message and close the connection */
|
||||||
|
|
|
@ -1,464 +1,5 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
* are permitted provided that the following conditions are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
||||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
||||||
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
|
||||||
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
||||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
||||||
* OF SUCH DAMAGE.
|
|
||||||
*
|
|
||||||
* This file is part of the lwIP TCP/IP stack.
|
|
||||||
*
|
|
||||||
* Author: Simon Goldschmidt
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
#ifndef __LWIPOPTS_H__
|
|
||||||
#define __LWIPOPTS_H__
|
|
||||||
|
|
||||||
#define LWIP_ESP 1
|
|
||||||
#define ESP_RTOS 1
|
|
||||||
#define PBUF_RSV_FOR_WLAN 1
|
|
||||||
#define EBUF_LWIP 1
|
|
||||||
#define ESP_TIMEWAIT_THRESHOLD 10000
|
|
||||||
#define LWIP_TIMEVAL_PRIVATE 0
|
|
||||||
|
|
||||||
#define TCP_WND (TCP_MSS * 2)
|
|
||||||
|
|
||||||
#define LWIP_IGMP 1
|
#define LWIP_IGMP 1
|
||||||
#include <stdint.h>
|
|
||||||
#include <esp/hwrand.h>
|
|
||||||
#define LWIP_RAND hwrand
|
|
||||||
|
|
||||||
/*
|
/* Use the defaults for everything else */
|
||||||
-----------------------------------------------
|
#include_next <lwipopts.h>
|
||||||
---------- Platform specific locking ----------
|
|
||||||
-----------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain
|
|
||||||
* critical regions during buffer allocation, deallocation and memory
|
|
||||||
* allocation and deallocation.
|
|
||||||
*/
|
|
||||||
#define SYS_LIGHTWEIGHT_PROT 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MEMCPY: override this if you have a faster implementation at hand than the
|
|
||||||
* one included in your C library
|
|
||||||
*/
|
|
||||||
#define MEMCPY(dst,src,len) memcpy(dst,src,len)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a
|
|
||||||
* call to memcpy() if the length is known at compile time and is small.
|
|
||||||
*/
|
|
||||||
#define SMEMCPY(dst,src,len) memcpy(dst,src,len)
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------
|
|
||||||
---------- Memory options ----------
|
|
||||||
------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library
|
|
||||||
* instead of the lwip internal allocator. Can save code size if you
|
|
||||||
* already use it.
|
|
||||||
*/
|
|
||||||
#define MEM_LIBC_MALLOC 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator.
|
|
||||||
* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution
|
|
||||||
* speed and usage from interrupts!
|
|
||||||
*/
|
|
||||||
#define MEMP_MEM_MALLOC 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MEM_ALIGNMENT: should be set to the alignment of the CPU
|
|
||||||
* 4 byte alignment -> #define MEM_ALIGNMENT 4
|
|
||||||
* 2 byte alignment -> #define MEM_ALIGNMENT 2
|
|
||||||
*/
|
|
||||||
#define MEM_ALIGNMENT 4
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------------------
|
|
||||||
---------- Internal Memory Pool Sizes ----------
|
|
||||||
------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
--------------------------------
|
|
||||||
---------- ARP options -------
|
|
||||||
--------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address
|
|
||||||
* resolution. By default, only the most recent packet is queued per IP address.
|
|
||||||
* This is sufficient for most protocols and mainly reduces TCP connection
|
|
||||||
* startup time. Set this to 1 if you know your application sends more than one
|
|
||||||
* packet in a row to an IP address that is not in the ARP cache.
|
|
||||||
*/
|
|
||||||
#define ARP_QUEUEING 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
--------------------------------
|
|
||||||
---------- IP options ----------
|
|
||||||
--------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that
|
|
||||||
* this option does not affect outgoing packet sizes, which can be controlled
|
|
||||||
* via IP_FRAG.
|
|
||||||
*/
|
|
||||||
#define IP_REASSEMBLY 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note
|
|
||||||
* that this option does not affect incoming packet sizes, which can be
|
|
||||||
* controlled via IP_REASSEMBLY.
|
|
||||||
*/
|
|
||||||
#define IP_FRAG 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)
|
|
||||||
* a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived
|
|
||||||
* in this time, the whole packet is discarded.
|
|
||||||
*/
|
|
||||||
#define IP_REASS_MAXAGE 3
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.
|
|
||||||
* Since the received pbufs are enqueued, be sure to configure
|
|
||||||
* PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive
|
|
||||||
* packets even if the maximum amount of fragments is enqueued for reassembly!
|
|
||||||
*/
|
|
||||||
#define IP_REASS_MAX_PBUFS 10
|
|
||||||
|
|
||||||
/*
|
|
||||||
----------------------------------
|
|
||||||
---------- ICMP options ----------
|
|
||||||
----------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
---------------------------------
|
|
||||||
---------- RAW options ----------
|
|
||||||
---------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
----------------------------------
|
|
||||||
---------- DHCP options ----------
|
|
||||||
----------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* LWIP_DHCP==1: Enable DHCP module.
|
|
||||||
*/
|
|
||||||
#define LWIP_DHCP 1
|
|
||||||
|
|
||||||
#define LWIP_DHCP_BOOTP_FILE 0
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------
|
|
||||||
---------- AUTOIP options ----------
|
|
||||||
------------------------------------
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
----------------------------------
|
|
||||||
---------- SNMP options ----------
|
|
||||||
----------------------------------
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
----------------------------------
|
|
||||||
---------- IGMP options ----------
|
|
||||||
----------------------------------
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
----------------------------------
|
|
||||||
---------- DNS options -----------
|
|
||||||
----------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS
|
|
||||||
* transport.
|
|
||||||
*/
|
|
||||||
#define LWIP_DNS 1
|
|
||||||
|
|
||||||
#define DNS_TABLE_SIZE 1
|
|
||||||
#define DNS_MAX_NAME_LENGTH 128
|
|
||||||
|
|
||||||
/*
|
|
||||||
---------------------------------
|
|
||||||
---------- UDP options ----------
|
|
||||||
---------------------------------
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
---------------------------------
|
|
||||||
---------- TCP options ----------
|
|
||||||
---------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.
|
|
||||||
* Define to 0 if your device is low on memory.
|
|
||||||
*/
|
|
||||||
#define TCP_QUEUE_OOSEQ 0
|
|
||||||
|
|
||||||
/*
|
|
||||||
* LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all
|
|
||||||
* events (accept, sent, etc) that happen in the system.
|
|
||||||
* LWIP_CALLBACK_API==1: The PCB callback function is called directly
|
|
||||||
* for the event. This is the default.
|
|
||||||
*/
|
|
||||||
#define TCP_MSS 1460
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCP_MAXRTX: Maximum number of retransmissions of data segments.
|
|
||||||
*/
|
|
||||||
#define TCP_MAXRTX 6
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.
|
|
||||||
*/
|
|
||||||
#define TCP_SYNMAXRTX 3
|
|
||||||
|
|
||||||
/*
|
|
||||||
----------------------------------
|
|
||||||
---------- Pbuf options ----------
|
|
||||||
----------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------------------
|
|
||||||
---------- Network Interfaces options ----------
|
|
||||||
------------------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data
|
|
||||||
* to be sent into one single pbuf. This is for compatibility with DMA-enabled
|
|
||||||
* MACs that do not support scatter-gather.
|
|
||||||
* Beware that this might involve CPU-memcpy before transmitting that would not
|
|
||||||
* be needed without this flag! Use this only if you need to!
|
|
||||||
*
|
|
||||||
* @todo: TCP and IP-frag do not work with this, yet:
|
|
||||||
*/
|
|
||||||
#define LWIP_NETIF_TX_SINGLE_PBUF 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------
|
|
||||||
---------- LOOPIF options ----------
|
|
||||||
------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------
|
|
||||||
---------- SLIPIF options ----------
|
|
||||||
------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------
|
|
||||||
---------- Thread options ----------
|
|
||||||
------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.
|
|
||||||
* The stack size value itself is platform-dependent, but is passed to
|
|
||||||
* sys_thread_new() when the thread is created.
|
|
||||||
*/
|
|
||||||
#define TCPIP_THREAD_STACKSIZE 512 //not ok:384
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.
|
|
||||||
* The priority value itself is platform-dependent, but is passed to
|
|
||||||
* sys_thread_new() when the thread is created.
|
|
||||||
*/
|
|
||||||
#define TCPIP_THREAD_PRIO (configMAX_PRIORITIES-5)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages
|
|
||||||
* The queue size value itself is platform-dependent, but is passed to
|
|
||||||
* sys_mbox_new() when tcpip_init is called.
|
|
||||||
*/
|
|
||||||
#define TCPIP_MBOX_SIZE 16
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
|
|
||||||
* NETCONN_UDP. The queue size value itself is platform-dependent, but is passed
|
|
||||||
* to sys_mbox_new() when the recvmbox is created.
|
|
||||||
*/
|
|
||||||
#define DEFAULT_UDP_RECVMBOX_SIZE 6
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a
|
|
||||||
* NETCONN_TCP. The queue size value itself is platform-dependent, but is passed
|
|
||||||
* to sys_mbox_new() when the recvmbox is created.
|
|
||||||
*/
|
|
||||||
#define DEFAULT_TCP_RECVMBOX_SIZE 6
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.
|
|
||||||
* The queue size value itself is platform-dependent, but is passed to
|
|
||||||
* sys_mbox_new() when the acceptmbox is created.
|
|
||||||
*/
|
|
||||||
#define DEFAULT_ACCEPTMBOX_SIZE 6
|
|
||||||
|
|
||||||
/*
|
|
||||||
----------------------------------------------
|
|
||||||
---------- Sequential layer options ----------
|
|
||||||
----------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
------------------------------------
|
|
||||||
---------- Socket options ----------
|
|
||||||
------------------------------------
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and
|
|
||||||
* SO_SNDTIMEO processing.
|
|
||||||
*/
|
|
||||||
#define LWIP_SO_SNDTIMEO 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and
|
|
||||||
* SO_RCVTIMEO processing.
|
|
||||||
*/
|
|
||||||
#define LWIP_SO_RCVTIMEO 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
|
|
||||||
* options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
|
|
||||||
* in seconds. (does not require sockets.c, and will affect tcp.c)
|
|
||||||
*/
|
|
||||||
#define LWIP_TCP_KEEPALIVE 1
|
|
||||||
|
|
||||||
/**
|
|
||||||
* LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.
|
|
||||||
*/
|
|
||||||
#define LWIP_SO_RCVBUF 0
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SO_REUSE==1: Enable SO_REUSEADDR option.
|
|
||||||
*/
|
|
||||||
#define SO_REUSE 1
|
|
||||||
|
|
||||||
/*
|
|
||||||
----------------------------------------
|
|
||||||
---------- Statistics options ----------
|
|
||||||
----------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
---------------------------------
|
|
||||||
---------- PPP options ----------
|
|
||||||
---------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
--------------------------------------
|
|
||||||
---------- Checksum options ----------
|
|
||||||
--------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
---------------------------------------
|
|
||||||
---------- IPv6 options ---------------
|
|
||||||
---------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
---------------------------------------
|
|
||||||
---------- Hook options ---------------
|
|
||||||
---------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
---------------------------------------
|
|
||||||
---------- Debugging options ----------
|
|
||||||
---------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Uncomment this line, and set the individual debug options you want, for IP stack debug output
|
|
||||||
//#define LWIP_DEBUG
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ETHARP_DEBUG: Enable debugging in etharp.c.
|
|
||||||
*/
|
|
||||||
#define ETHARP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PBUF_DEBUG: Enable debugging in pbuf.c.
|
|
||||||
*/
|
|
||||||
#define PBUF_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* API_LIB_DEBUG: Enable debugging in api_lib.c.
|
|
||||||
*/
|
|
||||||
#define API_LIB_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SOCKETS_DEBUG: Enable debugging in sockets.c.
|
|
||||||
*/
|
|
||||||
#define SOCKETS_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IP_DEBUG: Enable debugging for IP.
|
|
||||||
*/
|
|
||||||
#define IP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MEMP_DEBUG: Enable debugging in memp.c.
|
|
||||||
*/
|
|
||||||
#define MEMP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.
|
|
||||||
*/
|
|
||||||
#define TCP_INPUT_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.
|
|
||||||
*/
|
|
||||||
#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UDP_DEBUG: Enable debugging in udp.c.
|
|
||||||
*/
|
|
||||||
#define UDP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ICMP_DEBUG: Enable debugging in udp.c.
|
|
||||||
*/
|
|
||||||
#define ICMP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TCPIP_DEBUG: Enable debugging in tcpip.c.
|
|
||||||
*/
|
|
||||||
#define TCPIP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DHCP_DEBUG: Enable debugging in dhcp.c.
|
|
||||||
*/
|
|
||||||
#define DHCP_DEBUG LWIP_DBG_OFF
|
|
||||||
|
|
||||||
#define LWIP_POSIX_SOCKETS_IO_NAMES 0
|
|
||||||
|
|
||||||
#endif /* __LWIPOPTS_H__ */
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <lwip/udp.h>
|
#include <lwip/udp.h>
|
||||||
#include <lwip/igmp.h>
|
#include <lwip/igmp.h>
|
||||||
|
#include <lwip/ip_addr.h>
|
||||||
#include <espressif/esp_common.h>
|
#include <espressif/esp_common.h>
|
||||||
#include "upnp.h"
|
#include "upnp.h"
|
||||||
|
|
||||||
|
@ -18,13 +19,13 @@ static const char* get_my_ip(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function joins a multicast group witht he specified ip/port
|
* @brief This function joins a multicast group with the specified ip/port
|
||||||
* @param group_ip the specified multicast group ip
|
* @param group_ip the specified multicast group ip
|
||||||
* @param group_port the specified multicast port number
|
* @param group_port the specified multicast port number
|
||||||
* @param recv the lwip UDP callback
|
* @param recv the lwip UDP callback
|
||||||
* @retval udp_pcb* or NULL if joining failed
|
* @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, struct ip_addr * addr, u16_t port))
|
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;
|
bool status = false;
|
||||||
struct udp_pcb *upcb;
|
struct udp_pcb *upcb;
|
||||||
|
@ -36,7 +37,7 @@ static struct udp_pcb* mcast_join_group(char *group_ip, uint16_t group_port, voi
|
||||||
printf("Error, udp_new failed");
|
printf("Error, udp_new failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
udp_bind(upcb, IP_ADDR_ANY, group_port);
|
udp_bind(upcb, IP4_ADDR_ANY, group_port);
|
||||||
struct netif* netif = sdk_system_get_netif(STATION_IF);
|
struct netif* netif = sdk_system_get_netif(STATION_IF);
|
||||||
if (!netif) {
|
if (!netif) {
|
||||||
printf("Error, netif is null");
|
printf("Error, netif is null");
|
||||||
|
@ -46,10 +47,10 @@ static struct udp_pcb* mcast_join_group(char *group_ip, uint16_t group_port, voi
|
||||||
netif->flags |= NETIF_FLAG_IGMP;
|
netif->flags |= NETIF_FLAG_IGMP;
|
||||||
igmp_start(netif);
|
igmp_start(netif);
|
||||||
}
|
}
|
||||||
ip_addr_t ipgroup;
|
ip4_addr_t ipgroup;
|
||||||
ipaddr_aton(group_ip, &ipgroup);
|
ip4addr_aton(group_ip, &ipgroup);
|
||||||
err_t err = igmp_joingroup(&netif->ip_addr, &ipgroup);
|
err_t err = igmp_joingroup_netif(netif, &ipgroup);
|
||||||
if(ERR_OK != err) {
|
if (ERR_OK != err) {
|
||||||
printf("Failed to join multicast group: %d", err);
|
printf("Failed to join multicast group: %d", err);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +69,7 @@ static struct udp_pcb* mcast_join_group(char *group_ip, uint16_t group_port, voi
|
||||||
return upcb;
|
return upcb;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send(struct udp_pcb *upcb, struct ip_addr *addr, u16_t port)
|
static void send_udp(struct udp_pcb *upcb, const ip_addr_t *addr, u16_t port)
|
||||||
{
|
{
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
char msg[500];
|
char msg[500];
|
||||||
|
@ -110,14 +111,14 @@ static void send(struct udp_pcb *upcb, struct ip_addr *addr, u16_t port)
|
||||||
* @param port the remote port from which the packet was received
|
* @param port the remote port from which the packet was received
|
||||||
* @retval None
|
* @retval None
|
||||||
*/
|
*/
|
||||||
static void receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
|
static void receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||||
{
|
{
|
||||||
if (p) {
|
if (p) {
|
||||||
printf("Msg received port:%d len:%d\n", port, p->len);
|
printf("Msg received port:%d len:%d\n", port, p->len);
|
||||||
uint8_t *buf = (uint8_t*) p->payload;
|
uint8_t *buf = (uint8_t*) p->payload;
|
||||||
printf("Msg received port:%d len:%d\nbuf: %s\n", port, p->len, buf);
|
printf("Msg received port:%d len:%d\nbuf: %s\n", port, p->len, buf);
|
||||||
|
|
||||||
send(upcb, addr, port);
|
send_udp(upcb, addr, port);
|
||||||
|
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
}
|
}
|
||||||
|
|
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>"
|
1
examples/wificfg/local.mk
Normal file
1
examples/wificfg/local.mk
Normal file
|
@ -0,0 +1 @@
|
||||||
|
FLASH_SIZE ?= 32
|
94
examples/wificfg/wificfg.c
Normal file
94
examples/wificfg/wificfg.c
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* Example Wifi configuration via an access point.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 OurAirQuality.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0, January 2004 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/
|
||||||
|
*
|
||||||
|
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <espressif/esp_common.h>
|
||||||
|
#include <espressif/user_interface.h>
|
||||||
|
#include <esp/uart.h>
|
||||||
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
|
||||||
|
#include "wificfg/wificfg.h"
|
||||||
|
|
||||||
|
#include "sysparam.h"
|
||||||
|
|
||||||
|
static const char http_success_header[] = "HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
|
"Cache-Control: no-store\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n";
|
||||||
|
static const char *http_index_content[] = {
|
||||||
|
#include "content/index.html"
|
||||||
|
};
|
||||||
|
|
||||||
|
static int handle_index(int s, wificfg_method method,
|
||||||
|
uint32_t content_length,
|
||||||
|
wificfg_content_type content_type,
|
||||||
|
char *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (wificfg_write_string(s, http_success_header) < 0) return -1;
|
||||||
|
|
||||||
|
if (method != HTTP_METHOD_HEAD) {
|
||||||
|
if (wificfg_write_string_chunk(s, http_index_content[0], buf, len) < 0) return -1;
|
||||||
|
if (wificfg_write_html_title(s, buf, len, "Home") < 0) return -1;
|
||||||
|
if (wificfg_write_string_chunk(s, http_index_content[1], buf, len) < 0) return -1;
|
||||||
|
|
||||||
|
socklen_t addr_len;
|
||||||
|
struct sockaddr addr;
|
||||||
|
addr_len = sizeof(addr);
|
||||||
|
getpeername(s, (struct sockaddr*)&addr, &addr_len);
|
||||||
|
|
||||||
|
if (wificfg_write_string_chunk(s, "<dl class=\"dlh\">", buf, len) < 0) return -1;
|
||||||
|
if (addr.sa_family == AF_INET) {
|
||||||
|
struct sockaddr_in *sa = (struct sockaddr_in *)&addr;
|
||||||
|
if (wificfg_write_string_chunk(s, "<dt>Peer address</dt>", buf, len) < 0) return -1;
|
||||||
|
snprintf(buf, len, "<dd>" IPSTR " : %d</dd>",
|
||||||
|
IP2STR((ip4_addr_t *)&sa->sin_addr.s_addr), ntohs(sa->sin_port));
|
||||||
|
if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wificfg_write_string_chunk(s, "</dl>", buf, len) < 0) return -1;
|
||||||
|
if (wificfg_write_string_chunk(s, http_index_content[2], buf, len) < 0) return -1;
|
||||||
|
if (wificfg_write_chunk_end(s) < 0) return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const wificfg_dispatch dispatch_list[] = {
|
||||||
|
{"/", HTTP_METHOD_GET, handle_index, false},
|
||||||
|
{"/index.html", HTTP_METHOD_GET, handle_index, false},
|
||||||
|
{NULL, HTTP_METHOD_ANY, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
printf("SDK version:%s\n", sdk_system_get_sdk_version());
|
||||||
|
|
||||||
|
sdk_wifi_set_sleep_type(WIFI_SLEEP_MODEM);
|
||||||
|
|
||||||
|
wificfg_init(80, dispatch_list);
|
||||||
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include "ws2812_i2s/ws2812_i2s.h"
|
#include "ws2812_i2s/ws2812_i2s.h"
|
||||||
|
|
||||||
const uint32_t led_number = 60;
|
const uint32_t led_number = 12;
|
||||||
const uint32_t tail_fade_factor = 2;
|
const uint32_t tail_fade_factor = 2;
|
||||||
const uint32_t tail_length = 8;
|
const uint32_t tail_length = 8;
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ static int fix_index(int index)
|
||||||
|
|
||||||
static ws2812_pixel_t next_colour()
|
static ws2812_pixel_t next_colour()
|
||||||
{
|
{
|
||||||
ws2812_pixel_t colour = {0, 0, 0};
|
ws2812_pixel_t colour = {0, 0, 0, 0};
|
||||||
colour.red = rand() % 256;
|
colour.red = rand() % 256;
|
||||||
colour.green = rand() % 256;
|
colour.green = rand() % 256;
|
||||||
colour.blue = rand() % 256;
|
colour.blue = rand() % 256;
|
||||||
|
@ -54,7 +54,7 @@ static void demo(void *pvParameters)
|
||||||
ws2812_pixel_t pixels[led_number];
|
ws2812_pixel_t pixels[led_number];
|
||||||
int head_index = 0;
|
int head_index = 0;
|
||||||
|
|
||||||
ws2812_i2s_init(led_number);
|
ws2812_i2s_init(led_number, PIXEL_RGB);
|
||||||
|
|
||||||
memset(pixels, 0, sizeof(ws2812_pixel_t) * led_number);
|
memset(pixels, 0, sizeof(ws2812_pixel_t) * led_number);
|
||||||
|
|
||||||
|
@ -69,8 +69,8 @@ static void demo(void *pvParameters)
|
||||||
memset(&pixels[fix_index(head_index - tail_length)], 0,
|
memset(&pixels[fix_index(head_index - tail_length)], 0,
|
||||||
sizeof(ws2812_pixel_t));
|
sizeof(ws2812_pixel_t));
|
||||||
|
|
||||||
ws2812_i2s_update(pixels);
|
ws2812_i2s_update(pixels, PIXEL_RGB);
|
||||||
vTaskDelay(20 / portTICK_PERIOD_MS);
|
vTaskDelay(50 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,14 @@ static void demo(void *pvParameters)
|
||||||
void user_init(void)
|
void user_init(void)
|
||||||
{
|
{
|
||||||
uart_set_baud(0, 115200);
|
uart_set_baud(0, 115200);
|
||||||
|
struct sdk_station_config config = {
|
||||||
|
.ssid = "Loading...",
|
||||||
|
.password = "morays59924_howitzer",
|
||||||
|
};
|
||||||
|
|
||||||
|
/* required to call wifi_set_opmode before station_set_config */
|
||||||
|
sdk_wifi_set_opmode(STATION_MODE);
|
||||||
|
sdk_wifi_station_set_config(&config);
|
||||||
|
|
||||||
xTaskCreate(&demo, "ws2812_i2s", 256, NULL, 10, NULL);
|
xTaskCreate(&demo, "ws2812_i2s", 256, NULL, 10, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,7 @@ bool bmp180_measure(i2c_dev_t *dev, bmp180_constants_t *c, int32_t *temperature,
|
||||||
if (!temperature && !pressure)
|
if (!temperature && !pressure)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Temperature is always needed, allso required for pressure only.
|
// Temperature is always needed, also required for pressure only.
|
||||||
//
|
//
|
||||||
// Calculation taken from BMP180 Datasheet
|
// Calculation taken from BMP180 Datasheet
|
||||||
int32_t UT, X1, X2, B5;
|
int32_t UT, X1, X2, B5;
|
||||||
|
|
|
@ -14,18 +14,28 @@
|
||||||
* BSD Licensed as described in the file LICENSE
|
* BSD Licensed as described in the file LICENSE
|
||||||
*/
|
*/
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
#include <FreeRTOS.h>
|
#include <FreeRTOS.h>
|
||||||
#include <task.h>
|
#include <task.h>
|
||||||
#include <lwip/netif.h>
|
#include <lwip/netif.h>
|
||||||
#include <lwip/api.h>
|
#include <lwip/api.h>
|
||||||
|
#include "esplibs/libmain.h"
|
||||||
|
|
||||||
|
#if (DHCP_DEBUG == LWIP_DBG_ON)
|
||||||
|
#define debug(s, ...) printf("%s: " s "\n", "DHCP", ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug(s, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
|
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
|
||||||
defaults to a 68 octet options field for its DHCP client, and most
|
defaults to a 68 octet options field for its DHCP client, and most
|
||||||
full-sized clients send us more than this. */
|
full-sized clients send us more than this. */
|
||||||
#define DHCP_OPTIONS_LEN 312
|
#define DHCP_OPTIONS_LEN 312
|
||||||
|
|
||||||
#include <lwip/dhcp.h>
|
#include <lwip/ip.h>
|
||||||
|
#include <lwip/prot/dhcp.h>
|
||||||
|
#include <lwip/prot/iana.h>
|
||||||
|
|
||||||
_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size");
|
_Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size");
|
||||||
|
|
||||||
|
@ -35,15 +45,20 @@ _Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 3
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
|
||||||
|
uint8_t active;
|
||||||
uint32_t expires;
|
uint32_t expires;
|
||||||
} dhcp_lease_t;
|
} dhcp_lease_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct netconn *nc;
|
struct netconn *nc;
|
||||||
uint8_t max_leases;
|
uint8_t max_leases;
|
||||||
ip_addr_t first_client_addr;
|
ip4_addr_t first_client_addr;
|
||||||
struct netif *server_if;
|
struct netif *server_if;
|
||||||
dhcp_lease_t *leases; /* length max_leases */
|
dhcp_lease_t *leases; /* length max_leases */
|
||||||
|
/* Optional router */
|
||||||
|
ip4_addr_t router;
|
||||||
|
/* Optional DNS server */
|
||||||
|
ip4_addr_t dns;
|
||||||
} server_state_t;
|
} server_state_t;
|
||||||
|
|
||||||
/* Only one DHCP server task can run at once, so we have global state
|
/* Only one DHCP server task can run at once, so we have global state
|
||||||
|
@ -68,39 +83,54 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u
|
||||||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr);
|
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr);
|
||||||
|
|
||||||
/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */
|
/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */
|
||||||
inline static void sprintf_ipaddr(const ip_addr_t *addr, char *dest)
|
inline static void sprintf_ipaddr(const ip4_addr_t *addr, char *dest)
|
||||||
{
|
{
|
||||||
if(addr == NULL)
|
if (addr == NULL)
|
||||||
sprintf(dest, "NULL");
|
sprintf(dest, "NULL");
|
||||||
else
|
else
|
||||||
sprintf(dest, "%d.%d.%d.%d", ip4_addr1(addr),
|
sprintf(dest, "%d.%d.%d.%d", ip4_addr1(addr),
|
||||||
ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr));
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases)
|
void dhcpserver_start(const ip4_addr_t *first_client_addr, uint8_t max_leases)
|
||||||
{
|
{
|
||||||
/* Stop any existing running dhcpserver */
|
/* Stop any existing running dhcpserver */
|
||||||
if(dhcpserver_task_handle)
|
if (dhcpserver_task_handle)
|
||||||
dhcpserver_stop();
|
dhcpserver_stop();
|
||||||
|
|
||||||
state = malloc(sizeof(server_state_t));
|
state = malloc(sizeof(server_state_t));
|
||||||
state->max_leases = max_leases;
|
state->max_leases = max_leases;
|
||||||
state->leases = calloc(max_leases, sizeof(dhcp_lease_t));
|
state->leases = calloc(max_leases, sizeof(dhcp_lease_t));
|
||||||
|
bzero(state->leases, max_leases * sizeof(dhcp_lease_t));
|
||||||
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
|
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
|
||||||
ip_addr_copy(state->first_client_addr, *first_client_addr);
|
ip4_addr_copy(state->first_client_addr, *first_client_addr);
|
||||||
|
|
||||||
xTaskCreate(dhcpserver_task, "DHCPServer", 768, NULL, 8, &dhcpserver_task_handle);
|
/* Clear options */
|
||||||
|
ip4_addr_set_zero(&state->router);
|
||||||
|
ip4_addr_set_zero(&state->dns);
|
||||||
|
|
||||||
|
xTaskCreate(dhcpserver_task, "DHCP Server", 448, NULL, 2, &dhcpserver_task_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dhcpserver_stop(void)
|
void dhcpserver_stop(void)
|
||||||
{
|
{
|
||||||
if(dhcpserver_task_handle) {
|
if (dhcpserver_task_handle) {
|
||||||
vTaskDelete(dhcpserver_task_handle);
|
vTaskDelete(dhcpserver_task_handle);
|
||||||
free(state);
|
free(state);
|
||||||
dhcpserver_task_handle = NULL;
|
dhcpserver_task_handle = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dhcpserver_set_router(const ip4_addr_t *router)
|
||||||
|
{
|
||||||
|
ip4_addr_copy(state->router, *router);
|
||||||
|
}
|
||||||
|
|
||||||
|
void dhcpserver_set_dns(const ip4_addr_t *dns)
|
||||||
|
{
|
||||||
|
ip4_addr_copy(state->dns, *dns);
|
||||||
|
}
|
||||||
|
|
||||||
static void dhcpserver_task(void *pxParameter)
|
static void dhcpserver_task(void *pxParameter)
|
||||||
{
|
{
|
||||||
/* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */
|
/* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */
|
||||||
|
@ -108,11 +138,12 @@ static void dhcpserver_task(void *pxParameter)
|
||||||
|
|
||||||
state->nc = netconn_new (NETCONN_UDP);
|
state->nc = netconn_new (NETCONN_UDP);
|
||||||
if(!state->nc) {
|
if(!state->nc) {
|
||||||
printf("DHCP Server Error: Failed to allocate socket.\r\n");
|
debug("DHCP Server Error: Failed to allocate socket.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
netconn_bind(state->nc, IP_ADDR_ANY, DHCP_SERVER_PORT);
|
netconn_bind(state->nc, IP4_ADDR_ANY, LWIP_IANA_PORT_DHCP_SERVER);
|
||||||
|
netconn_bind_if (state->nc, netif_get_index(state->server_if));
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
@ -122,29 +153,32 @@ static void dhcpserver_task(void *pxParameter)
|
||||||
/* Receive a DHCP packet */
|
/* Receive a DHCP packet */
|
||||||
err_t err = netconn_recv(state->nc, &netbuf);
|
err_t err = netconn_recv(state->nc, &netbuf);
|
||||||
if(err != ERR_OK) {
|
if(err != ERR_OK) {
|
||||||
printf("DHCP Server Error: Failed to receive DHCP packet. err=%d\r\n", err);
|
debug("DHCP Server Error: Failed to receive DHCP packet. err=%d", err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* expire any leases that have passed */
|
/* expire any leases that have passed */
|
||||||
uint32_t now = xTaskGetTickCount();
|
uint32_t now = xTaskGetTickCount();
|
||||||
for(int i = 0; i < state->max_leases; i++) {
|
for (int i = 0; i < state->max_leases; i++) {
|
||||||
uint32_t expires = state->leases[i].expires;
|
if (state->leases[i].active) {
|
||||||
if(expires && expires < now)
|
uint32_t expires = state->leases[i].expires - now;
|
||||||
state->leases[i].expires = 0;
|
if (expires >= 0x80000000) {
|
||||||
|
state->leases[i].active = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ip_addr_t received_ip;
|
ip_addr_t received_ip;
|
||||||
u16_t port;
|
u16_t port;
|
||||||
netconn_addr(state->nc, &received_ip, &port);
|
netconn_addr(state->nc, &received_ip, &port);
|
||||||
|
|
||||||
if(netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
if (netbuf_len(netbuf) < offsetof(struct dhcp_msg, options)) {
|
||||||
/* too short to be a valid DHCP client message */
|
/* too short to be a valid DHCP client message */
|
||||||
netbuf_delete(netbuf);
|
netbuf_delete(netbuf);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) {
|
if(netbuf_len(netbuf) >= sizeof(struct dhcp_msg)) {
|
||||||
printf("DHCP Server Warning: Client sent more options than we know how to parse. len=%d\r\n", netbuf_len(netbuf));
|
debug("DHCP Server Warning: Client sent more options than we know how to parse. len=%d", netbuf_len(netbuf));
|
||||||
}
|
}
|
||||||
|
|
||||||
netbuf_copy(netbuf, &received, sizeof(struct dhcp_msg));
|
netbuf_copy(netbuf, &received, sizeof(struct dhcp_msg));
|
||||||
|
@ -153,18 +187,19 @@ static void dhcpserver_task(void *pxParameter)
|
||||||
uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE,
|
uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE,
|
||||||
DHCP_OPTION_MESSAGE_TYPE_LEN, NULL);
|
DHCP_OPTION_MESSAGE_TYPE_LEN, NULL);
|
||||||
if(!message_type) {
|
if(!message_type) {
|
||||||
printf("DHCP Server Error: No message type field found");
|
debug("DHCP Server Error: No message type field found");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if (DHCP_DEBUG == LWIP_DBG_ON)
|
||||||
printf("State dump. Message type %d\n", *message_type);
|
debug("State dump. Message type %d", *message_type);
|
||||||
for(int i = 0; i < state->max_leases; i++) {
|
for(int i = 0; i < state->max_leases; i++) {
|
||||||
dhcp_lease_t *lease = &state->leases[i];
|
dhcp_lease_t *lease = &state->leases[i];
|
||||||
printf("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, lease->expires, lease->hwaddr[0],
|
debug("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x", i, lease->expires, lease->hwaddr[0],
|
||||||
lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4],
|
||||||
lease->hwaddr[5]);
|
lease->hwaddr[5]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
switch(*message_type) {
|
switch(*message_type) {
|
||||||
case DHCP_DISCOVER:
|
case DHCP_DISCOVER:
|
||||||
|
@ -175,8 +210,9 @@ static void dhcpserver_task(void *pxParameter)
|
||||||
break;
|
break;
|
||||||
case DHCP_RELEASE:
|
case DHCP_RELEASE:
|
||||||
handle_dhcp_release(&received);
|
handle_dhcp_release(&received);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("DHCP Server Error: Unsupported message type %d\r\n", *message_type);
|
debug("DHCP Server Error: Unsupported message type %d", *message_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,14 +220,14 @@ static void dhcpserver_task(void *pxParameter)
|
||||||
|
|
||||||
static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
||||||
{
|
{
|
||||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
|
||||||
return;
|
return;
|
||||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr);
|
dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr);
|
||||||
if(!freelease) {
|
if(!freelease) {
|
||||||
printf("DHCP Server: All leases taken.\r\n");
|
debug("DHCP Server: All leases taken.");
|
||||||
return; /* Nothing available, so do nothing */
|
return; /* Nothing available, so do nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,13 +235,19 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
||||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||||
|
|
||||||
ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr);
|
dhcpmsg->yiaddr.addr = lwip_htonl(lwip_ntohl(state->first_client_addr.addr) + (freelease - state->leases));
|
||||||
ip4_addr4(&(dhcpmsg->yiaddr)) += (freelease - state->leases);
|
|
||||||
|
|
||||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_OFFER);
|
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_OFFER);
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||||
|
if (!ip4_addr_isany_val(state->router)) {
|
||||||
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
|
||||||
|
}
|
||||||
|
if (!ip4_addr_isany_val(state->dns)) {
|
||||||
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
|
||||||
|
}
|
||||||
|
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||||
|
|
||||||
struct netbuf *netbuf = netbuf_new();
|
struct netbuf *netbuf = netbuf_new();
|
||||||
|
@ -218,60 +260,64 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg)
|
||||||
static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
||||||
{
|
{
|
||||||
static char ipbuf[16];
|
static char ipbuf[16];
|
||||||
if(dhcpmsg->htype != DHCP_HTYPE_ETH)
|
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
|
||||||
return;
|
return;
|
||||||
if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ip_addr_t requested_ip;
|
ip4_addr_t requested_ip;
|
||||||
uint8_t *requested_ip_opt = find_dhcp_option(dhcpmsg, DHCP_OPTION_REQUESTED_IP, 4, NULL);
|
uint8_t *requested_ip_opt = find_dhcp_option(dhcpmsg, DHCP_OPTION_REQUESTED_IP, 4, NULL);
|
||||||
if(requested_ip_opt) {
|
if (requested_ip_opt) {
|
||||||
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
memcpy(&requested_ip.addr, requested_ip_opt, 4);
|
||||||
} else if(ip_addr_cmp(&requested_ip, IP_ADDR_ANY)) {
|
} else if (ip4_addr_cmp(&requested_ip, IP4_ADDR_ANY4)) {
|
||||||
ip_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
ip4_addr_copy(requested_ip, dhcpmsg->ciaddr);
|
||||||
} else {
|
} else {
|
||||||
printf("DHCP Server Error: No requested IP\r\n");
|
debug("DHCP Server Error: No requested IP");
|
||||||
send_dhcp_nak(dhcpmsg);
|
send_dhcp_nak(dhcpmsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Test the first 4 octets match */
|
/* Test the first 4 octets match */
|
||||||
if(ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
if (ip4_addr1(&requested_ip) != ip4_addr1(&state->first_client_addr)
|
||||||
|| ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr)
|
|| ip4_addr2(&requested_ip) != ip4_addr2(&state->first_client_addr)
|
||||||
|| ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) {
|
|| ip4_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) {
|
||||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||||
printf("DHCP Server Error: %s not an allowed IP\r\n", ipbuf);
|
debug("DHCP Server Error: %s not an allowed IP", ipbuf);
|
||||||
send_dhcp_nak(dhcpmsg);
|
send_dhcp_nak(dhcpmsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Test the last octet is in the MAXCLIENTS range */
|
/* Test the last octet is in the MAXCLIENTS range */
|
||||||
int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&state->first_client_addr);
|
int16_t octet_offs = ip4_addr4(&requested_ip) - ip4_addr4(&state->first_client_addr);
|
||||||
if(octet_offs < 0 || octet_offs >= state->max_leases) {
|
if(octet_offs < 0 || octet_offs >= state->max_leases) {
|
||||||
printf("DHCP Server Error: Address out of range\r\n");
|
debug("DHCP Server Error: Address out of range");
|
||||||
send_dhcp_nak(dhcpmsg);
|
send_dhcp_nak(dhcpmsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dhcp_lease_t *requested_lease = state->leases + octet_offs;
|
dhcp_lease_t *requested_lease = state->leases + octet_offs;
|
||||||
if(requested_lease->expires != 0 && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
if (requested_lease->active && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
|
||||||
{
|
{
|
||||||
printf("DHCP Server Error: Lease for address already taken\r\n");
|
debug("DHCP Server Error: Lease for address already taken");
|
||||||
send_dhcp_nak(dhcpmsg);
|
send_dhcp_nak(dhcpmsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen);
|
memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen);
|
||||||
sprintf_ipaddr(&requested_ip, ipbuf);
|
sprintf_ipaddr(&requested_ip, ipbuf);
|
||||||
printf("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", ipbuf, requested_lease->hwaddr[0],
|
debug("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x", ipbuf, requested_lease->hwaddr[0],
|
||||||
requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4],
|
requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4],
|
||||||
requested_lease->hwaddr[5]);
|
requested_lease->hwaddr[5]);
|
||||||
requested_lease->expires = DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
uint32_t now = xTaskGetTickCount();
|
||||||
|
requested_lease->expires = now + DHCPSERVER_LEASE_TIME * configTICK_RATE_HZ;
|
||||||
|
requested_lease->active = 1;
|
||||||
|
|
||||||
|
sdk_wifi_softap_set_station_info(requested_lease->hwaddr, &requested_ip);
|
||||||
|
|
||||||
/* Reuse the REQUEST message as the ACK message */
|
/* Reuse the REQUEST message as the ACK message */
|
||||||
dhcpmsg->op = DHCP_BOOTREPLY;
|
dhcpmsg->op = DHCP_BOOTREPLY;
|
||||||
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
|
||||||
|
|
||||||
ip_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
ip4_addr_copy(dhcpmsg->yiaddr, requested_ip);
|
||||||
|
|
||||||
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
|
||||||
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK);
|
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK);
|
||||||
|
@ -279,6 +325,13 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &state->server_if->ip_addr, 4);
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &state->server_if->netmask, 4);
|
||||||
|
if (!ip4_addr_isany_val(state->router)) {
|
||||||
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
|
||||||
|
}
|
||||||
|
if (!ip4_addr_isany_val(state->dns)) {
|
||||||
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
|
||||||
|
}
|
||||||
|
|
||||||
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
|
||||||
|
|
||||||
struct netbuf *netbuf = netbuf_new();
|
struct netbuf *netbuf = netbuf_new();
|
||||||
|
@ -291,7 +344,8 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg)
|
||||||
static void handle_dhcp_release(struct dhcp_msg *dhcpmsg)
|
static void handle_dhcp_release(struct dhcp_msg *dhcpmsg)
|
||||||
{
|
{
|
||||||
dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr);
|
dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr);
|
||||||
if(lease) {
|
if (lease) {
|
||||||
|
lease->active = 0;
|
||||||
lease->expires = 0;
|
lease->expires = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -319,17 +373,17 @@ static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8
|
||||||
uint8_t *start = (uint8_t *)&msg->options;
|
uint8_t *start = (uint8_t *)&msg->options;
|
||||||
uint8_t *msg_end = (uint8_t *)msg + sizeof(struct dhcp_msg);
|
uint8_t *msg_end = (uint8_t *)msg + sizeof(struct dhcp_msg);
|
||||||
|
|
||||||
for(uint8_t *p = start; p < msg_end-2;) {
|
for (uint8_t *p = start; p < msg_end-2;) {
|
||||||
uint8_t type = *p++;
|
uint8_t type = *p++;
|
||||||
uint8_t len = *p++;
|
uint8_t len = *p++;
|
||||||
if(type == DHCP_OPTION_END)
|
if (type == DHCP_OPTION_END)
|
||||||
return NULL;
|
return NULL;
|
||||||
if(p+len >= msg_end)
|
if (p+len >= msg_end)
|
||||||
break; /* We've overrun our valid DHCP message size, or this isn't a valid option */
|
break; /* We've overrun our valid DHCP message size, or this isn't a valid option */
|
||||||
if(type == option_num) {
|
if (type == option_num) {
|
||||||
if(len < min_length)
|
if (len < min_length)
|
||||||
break;
|
break;
|
||||||
if(length)
|
if (length)
|
||||||
*length = len;
|
*length = len;
|
||||||
return p; /* start of actual option data */
|
return p; /* start of actual option data */
|
||||||
}
|
}
|
||||||
|
@ -349,7 +403,7 @@ static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value)
|
||||||
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len)
|
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len)
|
||||||
{
|
{
|
||||||
*opt++ = type;
|
*opt++ = type;
|
||||||
if(len) {
|
if (len) {
|
||||||
*opt++ = len;
|
*opt++ = len;
|
||||||
memcpy(opt, value, len);
|
memcpy(opt, value, len);
|
||||||
}
|
}
|
||||||
|
@ -360,8 +414,8 @@ static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, u
|
||||||
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr)
|
static dhcp_lease_t *find_lease_slot(uint8_t *hwaddr)
|
||||||
{
|
{
|
||||||
dhcp_lease_t *empty_lease = NULL;
|
dhcp_lease_t *empty_lease = NULL;
|
||||||
for(int i = 0; i < state->max_leases; i++) {
|
for (int i = 0; i < state->max_leases; i++) {
|
||||||
if(state->leases[i].expires == 0 && !empty_lease)
|
if (!state->leases[i].active && !empty_lease)
|
||||||
empty_lease = &state->leases[i];
|
empty_lease = &state->leases[i];
|
||||||
else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0)
|
else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0)
|
||||||
return &state->leases[i];
|
return &state->leases[i];
|
||||||
|
|
|
@ -26,14 +26,20 @@ extern "C" {
|
||||||
to a client. Subsequent lease addresses are calculated by
|
to a client. Subsequent lease addresses are calculated by
|
||||||
incrementing the final octet of the IPv4 address, up to max_leases.
|
incrementing the final octet of the IPv4 address, up to max_leases.
|
||||||
*/
|
*/
|
||||||
void dhcpserver_start(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
void dhcpserver_start(const ip4_addr_t *first_client_addr, uint8_t max_leases);
|
||||||
|
|
||||||
void dhcpserver_get_lease(const ip_addr_t *first_client_addr, uint8_t max_leases);
|
void dhcpserver_get_lease(const ip4_addr_t *first_client_addr, uint8_t max_leases);
|
||||||
|
|
||||||
/* Stop DHCP server.
|
/* Stop DHCP server.
|
||||||
*/
|
*/
|
||||||
void dhcpserver_stop(void);
|
void dhcpserver_stop(void);
|
||||||
|
|
||||||
|
/* Set a router address to send as an option. */
|
||||||
|
void dhcpserver_set_router(const ip4_addr_t *router);
|
||||||
|
|
||||||
|
/* Set a DNS address to send as an option. */
|
||||||
|
void dhcpserver_set_dns(const ip4_addr_t *dns);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,13 +15,13 @@
|
||||||
/* Convert normal decimal to binary coded decimal */
|
/* Convert normal decimal to binary coded decimal */
|
||||||
static inline uint8_t decToBcd(uint8_t dec)
|
static inline uint8_t decToBcd(uint8_t dec)
|
||||||
{
|
{
|
||||||
return(((dec / 10) * 16) + (dec % 10));
|
return (dec / 10) * 16 + dec % 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert binary coded decimal to normal decimal */
|
/* Convert binary coded decimal to normal decimal */
|
||||||
static inline uint8_t bcdToDec(uint8_t bcd)
|
static inline uint8_t bcdToDec(uint8_t bcd)
|
||||||
{
|
{
|
||||||
return(((bcd / 16) * 10) + (bcd % 16));
|
return (bcd / 16) * 10 + bcd % 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send a number of bytes to the rtc over i2c
|
/* Send a number of bytes to the rtc over i2c
|
||||||
|
@ -48,6 +48,8 @@ int ds3231_setTime(i2c_dev_t *dev, struct tm *time)
|
||||||
data[0] = decToBcd(time->tm_sec);
|
data[0] = decToBcd(time->tm_sec);
|
||||||
data[1] = decToBcd(time->tm_min);
|
data[1] = decToBcd(time->tm_min);
|
||||||
data[2] = decToBcd(time->tm_hour);
|
data[2] = decToBcd(time->tm_hour);
|
||||||
|
/* The week data must be in the range 1 to 7, and to keep the start on the
|
||||||
|
* same day as for tm_wday have it start at 1 on Sunday. */
|
||||||
data[3] = decToBcd(time->tm_wday + 1);
|
data[3] = decToBcd(time->tm_wday + 1);
|
||||||
data[4] = decToBcd(time->tm_mday);
|
data[4] = decToBcd(time->tm_mday);
|
||||||
data[5] = decToBcd(time->tm_mon + 1);
|
data[5] = decToBcd(time->tm_mon + 1);
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
|
|
||||||
/** Set this to 1 on platforms where strnstr is not available */
|
/** Set this to 1 on platforms where strnstr is not available */
|
||||||
#ifndef LWIP_HTTPD_STRNSTR_PRIVATE
|
#ifndef LWIP_HTTPD_STRNSTR_PRIVATE
|
||||||
#define LWIP_HTTPD_STRNSTR_PRIVATE 1
|
#define LWIP_HTTPD_STRNSTR_PRIVATE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Set this to one to show error pages when parsing a request fails instead
|
/** Set this to one to show error pages when parsing a request fails instead
|
||||||
|
@ -2675,7 +2675,7 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
|
||||||
* Initialize the httpd with the specified local address.
|
* Initialize the httpd with the specified local address.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
httpd_init_addr(ip_addr_t *local_addr)
|
httpd_init_addr(const ip_addr_t *local_addr)
|
||||||
{
|
{
|
||||||
struct tcp_pcb *pcb;
|
struct tcp_pcb *pcb;
|
||||||
err_t err;
|
err_t err;
|
||||||
|
|
|
@ -2,11 +2,12 @@
|
||||||
|
|
||||||
This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
|
This time a driver for the excellent esp-open-rtos. This is a bit banging I2C driver based on the Wikipedia pesudo C code [1].
|
||||||
|
|
||||||
### Usage
|
### Basic usage
|
||||||
|
|
||||||
````
|
```C
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
|
|
||||||
|
#define BUS (0)
|
||||||
#define SCL_PIN (0)
|
#define SCL_PIN (0)
|
||||||
#define SDA_PIN (2)
|
#define SDA_PIN (2)
|
||||||
|
|
||||||
|
@ -14,19 +15,19 @@ uint8_t slave_addr = 0x20;
|
||||||
uint8_t reg_addr = 0x1f;
|
uint8_t reg_addr = 0x1f;
|
||||||
uint8_t reg_data;
|
uint8_t reg_data;
|
||||||
|
|
||||||
i2c_init(SCL_PIN, SDA_PIN);
|
i2c_init(BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
|
||||||
|
|
||||||
// Write 1 byte to slave register
|
// Write 1 byte to slave register
|
||||||
int err = i2c_slave_write(slave_addr, ®_addr, &data, 1);
|
int err = i2c_slave_write(BUS, slave_addr, ®_addr, &data, 1);
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
{
|
{
|
||||||
// do something with error
|
// do something with error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue write to slave, sending reg_addr, followed by reading 1 byte
|
// Issue write to slave, sending reg_addr, followed by reading 1 byte
|
||||||
err = i2c_slave_read(slave_addr, ®_addr, ®_data, 1);
|
err = i2c_slave_read(BUS, slave_addr, ®_addr, ®_data, 1);
|
||||||
|
|
||||||
````
|
```
|
||||||
|
|
||||||
For details please see `extras/i2c/i2c.h`.
|
For details please see `extras/i2c/i2c.h`.
|
||||||
|
|
||||||
|
|
102
extras/i2c/i2c.c
102
extras/i2c/i2c.c
|
@ -22,10 +22,13 @@
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "i2c.h"
|
||||||
|
|
||||||
#include <esp8266.h>
|
#include <esp8266.h>
|
||||||
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
#include <espressif/esp_misc.h> // sdk_os_delay_us
|
||||||
#include <espressif/esp_system.h>
|
#include <espressif/esp_system.h>
|
||||||
#include "i2c.h"
|
#include <FreeRTOS.h>
|
||||||
|
#include <task.h>
|
||||||
|
|
||||||
//#define I2C_DEBUG true
|
//#define I2C_DEBUG true
|
||||||
|
|
||||||
|
@ -37,7 +40,28 @@
|
||||||
|
|
||||||
#define CLK_STRETCH (10)
|
#define CLK_STRETCH (10)
|
||||||
|
|
||||||
static uint8_t freq ; // Store CPU frequency for optimisation speed in delay function ( Warning: Don't change CPU frequency during a transaction)
|
// Following array contain delay values for different frequencies
|
||||||
|
// Warning: 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
||||||
|
const static uint8_t i2c_freq_array[][2] = {
|
||||||
|
[I2C_FREQ_80K] = {255, 35},
|
||||||
|
[I2C_FREQ_100K] = {100, 20},
|
||||||
|
[I2C_FREQ_400K] = {10, 1},
|
||||||
|
[I2C_FREQ_500K] = {6, 1}
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t freq; // Store CPU frequency for optimisation speed in delay function (Warning: Don't change CPU frequency during a transaction)
|
||||||
|
|
||||||
|
// Bus settings
|
||||||
|
typedef struct i2c_bus_description
|
||||||
|
{
|
||||||
|
uint8_t g_scl_pin; // SCL pin
|
||||||
|
uint8_t g_sda_pin; // SDA pin
|
||||||
|
i2c_freq_t frequency; // Frequency
|
||||||
|
bool started;
|
||||||
|
bool flag;
|
||||||
|
bool force;
|
||||||
|
} i2c_bus_description_t;
|
||||||
|
|
||||||
static i2c_bus_description_t i2c_bus[MAX_I2C_BUS];
|
static i2c_bus_description_t i2c_bus[MAX_I2C_BUS];
|
||||||
|
|
||||||
inline bool i2c_status(uint8_t bus)
|
inline bool i2c_status(uint8_t bus)
|
||||||
|
@ -48,10 +72,10 @@ inline bool i2c_status(uint8_t bus)
|
||||||
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
||||||
{
|
{
|
||||||
i2c_bus[bus].started = false;
|
i2c_bus[bus].started = false;
|
||||||
i2c_bus[bus].flag = false ;
|
i2c_bus[bus].flag = false;
|
||||||
i2c_bus[bus].g_scl_pin = scl_pin;
|
i2c_bus[bus].g_scl_pin = scl_pin;
|
||||||
i2c_bus[bus].g_sda_pin = sda_pin;
|
i2c_bus[bus].g_sda_pin = sda_pin;
|
||||||
i2c_bus[bus].frequency = freq ;
|
i2c_bus[bus].frequency = freq;
|
||||||
|
|
||||||
// Just to prevent these pins floating too much if not connected.
|
// Just to prevent these pins floating too much if not connected.
|
||||||
gpio_set_pullup(i2c_bus[bus].g_scl_pin, 1, 1);
|
gpio_set_pullup(i2c_bus[bus].g_scl_pin, 1, 1);
|
||||||
|
@ -73,7 +97,7 @@ void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq)
|
||||||
|
|
||||||
void i2c_frequency(uint8_t bus, i2c_freq_t freq)
|
void i2c_frequency(uint8_t bus, i2c_freq_t freq)
|
||||||
{
|
{
|
||||||
i2c_bus[bus].frequency = freq ;
|
i2c_bus[bus].frequency = freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void i2c_delay(uint8_t bus)
|
static inline void i2c_delay(uint8_t bus)
|
||||||
|
@ -136,13 +160,14 @@ void i2c_start(uint8_t bus)
|
||||||
(void) read_sda(bus);
|
(void) read_sda(bus);
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
uint32_t clk_stretch = CLK_STRETCH;
|
uint32_t clk_stretch = CLK_STRETCH;
|
||||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
while (read_scl(bus) == 0 && clk_stretch--)
|
||||||
|
;
|
||||||
// Repeated start setup time, minimum 4.7us
|
// Repeated start setup time, minimum 4.7us
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
}
|
}
|
||||||
i2c_bus[bus].started = true;
|
i2c_bus[bus].started = true;
|
||||||
if (read_sda(bus) == 0) {
|
if (read_sda(bus) == 0) {
|
||||||
debug("arbitration lost in i2c_start from bus %u",bus);
|
debug("arbitration lost in i2c_start from bus %u", bus);
|
||||||
}
|
}
|
||||||
// SCL is high, set SDA from 1 to 0.
|
// SCL is high, set SDA from 1 to 0.
|
||||||
clear_sda(bus);
|
clear_sda(bus);
|
||||||
|
@ -158,17 +183,18 @@ bool i2c_stop(uint8_t bus)
|
||||||
clear_sda(bus);
|
clear_sda(bus);
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
// Clock stretching
|
// Clock stretching
|
||||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
while (read_scl(bus) == 0 && clk_stretch--)
|
||||||
|
;
|
||||||
// Stop bit setup time, minimum 4us
|
// Stop bit setup time, minimum 4us
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
// SCL is high, set SDA from 0 to 1
|
// SCL is high, set SDA from 0 to 1
|
||||||
if (read_sda(bus) == 0) {
|
if (read_sda(bus) == 0) {
|
||||||
debug("arbitration lost in i2c_stop from bus %u",bus);
|
debug("arbitration lost in i2c_stop from bus %u", bus);
|
||||||
}
|
}
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
if (!i2c_bus[bus].started) {
|
if (!i2c_bus[bus].started) {
|
||||||
debug("bus %u link was break!",bus);
|
debug("bus %u link was break!", bus);
|
||||||
return false ; //If bus was stop in other way, the current transmission Failed
|
return false; // If bus was stop in other way, the current transmission Failed
|
||||||
}
|
}
|
||||||
i2c_bus[bus].started = false;
|
i2c_bus[bus].started = false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -185,11 +211,12 @@ static void i2c_write_bit(uint8_t bus, bool bit)
|
||||||
}
|
}
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
// Clock stretching
|
// Clock stretching
|
||||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
while (read_scl(bus) == 0 && clk_stretch--)
|
||||||
|
;
|
||||||
// SCL is high, now data is valid
|
// SCL is high, now data is valid
|
||||||
// If SDA is high, check that nobody else is driving SDA
|
// If SDA is high, check that nobody else is driving SDA
|
||||||
if (bit && read_sda(bus) == 0) {
|
if (bit && read_sda(bus) == 0) {
|
||||||
debug("arbitration lost in i2c_write_bit from bus %u",bus);
|
debug("arbitration lost in i2c_write_bit from bus %u", bus);
|
||||||
}
|
}
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
clear_scl(bus);
|
clear_scl(bus);
|
||||||
|
@ -204,7 +231,8 @@ static bool i2c_read_bit(uint8_t bus)
|
||||||
(void) read_sda(bus);
|
(void) read_sda(bus);
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
// Clock stretching
|
// Clock stretching
|
||||||
while (read_scl(bus) == 0 && clk_stretch--) ;
|
while (read_scl(bus) == 0 && clk_stretch--)
|
||||||
|
;
|
||||||
// SCL is high, now data is valid
|
// SCL is high, now data is valid
|
||||||
bit = read_sda(bus);
|
bit = read_sda(bus);
|
||||||
i2c_delay(bus);
|
i2c_delay(bus);
|
||||||
|
@ -217,7 +245,7 @@ bool i2c_write(uint8_t bus, uint8_t byte)
|
||||||
bool nack;
|
bool nack;
|
||||||
uint8_t bit;
|
uint8_t bit;
|
||||||
for (bit = 0; bit < 8; bit++) {
|
for (bit = 0; bit < 8; bit++) {
|
||||||
i2c_write_bit(bus,(byte & 0x80) != 0);
|
i2c_write_bit(bus, (byte & 0x80) != 0);
|
||||||
byte <<= 1;
|
byte <<= 1;
|
||||||
}
|
}
|
||||||
nack = i2c_read_bit(bus);
|
nack = i2c_read_bit(bus);
|
||||||
|
@ -231,22 +259,22 @@ uint8_t i2c_read(uint8_t bus, bool ack)
|
||||||
for (bit = 0; bit < 8; bit++) {
|
for (bit = 0; bit < 8; bit++) {
|
||||||
byte = ((byte << 1)) | (i2c_read_bit(bus));
|
byte = ((byte << 1)) | (i2c_read_bit(bus));
|
||||||
}
|
}
|
||||||
i2c_write_bit(bus,ack);
|
i2c_write_bit(bus, ack);
|
||||||
return byte;
|
return byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_force_bus(uint8_t bus, bool state)
|
void i2c_force_bus(uint8_t bus, bool state)
|
||||||
{
|
{
|
||||||
i2c_bus[bus].force = state ;
|
i2c_bus[bus].force = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_bus_test(uint8_t bus)
|
static int i2c_bus_test(uint8_t bus)
|
||||||
{
|
{
|
||||||
taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it!
|
taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it!
|
||||||
bool status = i2c_bus[bus].flag ; // get current status
|
bool status = i2c_bus[bus].flag; // get current status
|
||||||
if(i2c_bus[bus].force)
|
if(i2c_bus[bus].force)
|
||||||
{
|
{
|
||||||
i2c_bus[bus].flag = true ; // force bus on
|
i2c_bus[bus].flag = true; // force bus on
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
if(status)
|
if(status)
|
||||||
i2c_stop(bus); //Bus was busy, stop it.
|
i2c_stop(bus); //Bus was busy, stop it.
|
||||||
|
@ -258,72 +286,72 @@ static int i2c_bus_test(uint8_t bus)
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
debug("busy");
|
debug("busy");
|
||||||
taskYIELD(); // If bus busy, change task to try finish last com.
|
taskYIELD(); // If bus busy, change task to try finish last com.
|
||||||
return -EBUSY ; // If bus busy, inform user
|
return -EBUSY; // If bus busy, inform user
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
i2c_bus[bus].flag = true ; // Set Bus busy
|
i2c_bus[bus].flag = true; // Set Bus busy
|
||||||
taskEXIT_CRITICAL();
|
taskEXIT_CRITICAL();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0 ;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len)
|
int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
if(i2c_bus_test(bus))
|
if(i2c_bus_test(bus))
|
||||||
return -EBUSY ;
|
return -EBUSY;
|
||||||
i2c_start(bus);
|
i2c_start(bus);
|
||||||
if (!i2c_write(bus, slave_addr << 1))
|
if (!i2c_write(bus, slave_addr << 1))
|
||||||
goto error;
|
goto error;
|
||||||
if(data != NULL)
|
if(data != NULL)
|
||||||
if (!i2c_write(bus,*data))
|
if (!i2c_write(bus, *data))
|
||||||
goto error;
|
goto error;
|
||||||
while (len--) {
|
while (len--) {
|
||||||
if (!i2c_write(bus,*buf++))
|
if (!i2c_write(bus, *buf++))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (!i2c_stop(bus))
|
if (!i2c_stop(bus))
|
||||||
goto error;
|
goto error;
|
||||||
i2c_bus[bus].flag = false ; // Bus free
|
i2c_bus[bus].flag = false; // Bus free
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
debug("Bus %u Write Error",bus);
|
debug("Bus %u Write Error", bus);
|
||||||
i2c_stop(bus);
|
i2c_stop(bus);
|
||||||
i2c_bus[bus].flag = false ; // Bus free
|
i2c_bus[bus].flag = false; // Bus free
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len)
|
int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len)
|
||||||
{
|
{
|
||||||
if(i2c_bus_test(bus))
|
if(i2c_bus_test(bus))
|
||||||
return -EBUSY ;
|
return -EBUSY;
|
||||||
if(data != NULL) {
|
if(data != NULL) {
|
||||||
i2c_start(bus);
|
i2c_start(bus);
|
||||||
if (!i2c_write(bus,slave_addr << 1))
|
if (!i2c_write(bus, slave_addr << 1))
|
||||||
goto error;
|
goto error;
|
||||||
if (!i2c_write(bus,*data))
|
if (!i2c_write(bus, *data))
|
||||||
goto error;
|
goto error;
|
||||||
if (!i2c_stop(bus))
|
if (!i2c_stop(bus))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
i2c_start(bus);
|
i2c_start(bus);
|
||||||
if (!i2c_write(bus,slave_addr << 1 | 1)) // Slave address + read
|
if (!i2c_write(bus, slave_addr << 1 | 1)) // Slave address + read
|
||||||
goto error;
|
goto error;
|
||||||
while(len) {
|
while(len) {
|
||||||
*buf = i2c_read(bus,len == 1);
|
*buf = i2c_read(bus, len == 1);
|
||||||
buf++;
|
buf++;
|
||||||
len--;
|
len--;
|
||||||
}
|
}
|
||||||
if (!i2c_stop(bus))
|
if (!i2c_stop(bus))
|
||||||
goto error;
|
goto error;
|
||||||
i2c_bus[bus].flag = false ; // Bus free
|
i2c_bus[bus].flag = false; // Bus free
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
debug("Read Error");
|
debug("Read Error");
|
||||||
i2c_stop(bus);
|
i2c_stop(bus);
|
||||||
i2c_bus[bus].flag = false ; // Bus free
|
i2c_bus[bus].flag = false; // Bus free
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,10 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* I2C driver for ESP8266 written for use with esp-open-rtos
|
||||||
|
* Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef __I2C_H__
|
#ifndef __I2C_H__
|
||||||
#define __I2C_H__
|
#define __I2C_H__
|
||||||
|
@ -28,62 +32,36 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <FreeRTOS.h>
|
|
||||||
#include <task.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* Define i2c bus max number
|
||||||
* Define i2c bus max number
|
|
||||||
*/
|
*/
|
||||||
#define MAX_I2C_BUS 2
|
#ifndef MAX_I2C_BUS
|
||||||
|
#define MAX_I2C_BUS 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum
|
||||||
/*
|
{
|
||||||
* following array contain value for different frequency
|
I2C_FREQ_80K = 0,//!< I2C_FREQ_80K
|
||||||
* Warning : 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz
|
I2C_FREQ_100K, //!< I2C_FREQ_100K
|
||||||
* Array format is { {160MHz, 80MHz} , {160MHz, 80MHz} , ... }
|
I2C_FREQ_400K, //!< I2C_FREQ_400K
|
||||||
*/
|
I2C_FREQ_500K, //!< I2C_FREQ_500K
|
||||||
#define NB_FREQ_AVAILABLE 4
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
I2C_FREQ_80K = 0,
|
|
||||||
I2C_FREQ_100K,
|
|
||||||
I2C_FREQ_400K,
|
|
||||||
I2C_FREQ_500K,
|
|
||||||
} i2c_freq_t;
|
} i2c_freq_t;
|
||||||
|
|
||||||
const static uint8_t i2c_freq_array[NB_FREQ_AVAILABLE][2] = { {255,35}, {100,20}, {10,1}, {6,1} } ;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Device descriptor
|
* Device descriptor
|
||||||
*/
|
*/
|
||||||
typedef struct i2c_dev {
|
typedef struct i2c_dev
|
||||||
uint8_t bus ;
|
{
|
||||||
uint8_t addr ;
|
uint8_t bus;
|
||||||
} i2c_dev_t ;
|
uint8_t addr;
|
||||||
|
} i2c_dev_t;
|
||||||
|
|
||||||
/**
|
/// Level 0 API
|
||||||
* Bus settings
|
|
||||||
*/
|
|
||||||
typedef struct i2c_bus_description {
|
|
||||||
uint8_t g_scl_pin; // Scl pin
|
|
||||||
uint8_t g_sda_pin; // Sda pin
|
|
||||||
uint8_t frequency; // frequency selection
|
|
||||||
bool started;
|
|
||||||
bool flag;
|
|
||||||
bool force;
|
|
||||||
} i2c_bus_description_t ;
|
|
||||||
|
|
||||||
|
|
||||||
// I2C driver for ESP8266 written for use with esp-open-rtos
|
|
||||||
// Based on https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol
|
|
||||||
// With calling overhead, we end up at ~320kbit/s
|
|
||||||
|
|
||||||
//Level 0 API
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init bitbanging I2C driver on given pins
|
* Init bitbanging I2C driver on given pins
|
||||||
|
@ -137,7 +115,7 @@ bool i2c_stop(uint8_t bus);
|
||||||
*/
|
*/
|
||||||
bool i2c_status(uint8_t bus);
|
bool i2c_status(uint8_t bus);
|
||||||
|
|
||||||
//Level 1 API (Don't need functions above)
|
/// Level 1 API (Don't need functions above)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function will allow you to force a transmission I2C, cancel current transmission.
|
* This function will allow you to force a transmission I2C, cancel current transmission.
|
||||||
|
|
|
@ -62,7 +62,7 @@ void sdk_rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id,
|
||||||
reg_add##_lsb, indata)
|
reg_add##_lsb, indata)
|
||||||
|
|
||||||
|
|
||||||
void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
void i2s_dma_init(i2s_dma_isr_t isr, void *arg, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
||||||
{
|
{
|
||||||
// reset DMA
|
// reset DMA
|
||||||
SET_MASK_BITS(SLC.CONF0, SLC_CONF0_RX_LINK_RESET);
|
SET_MASK_BITS(SLC.CONF0, SLC_CONF0_RX_LINK_RESET);
|
||||||
|
@ -83,7 +83,7 @@ void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins)
|
||||||
SLC_RX_DESCRIPTOR_CONF_RX_EOF_MODE | SLC_RX_DESCRIPTOR_CONF_RX_FILL_MODE);
|
SLC_RX_DESCRIPTOR_CONF_RX_EOF_MODE | SLC_RX_DESCRIPTOR_CONF_RX_FILL_MODE);
|
||||||
|
|
||||||
if (isr) {
|
if (isr) {
|
||||||
_xt_isr_attach(INUM_SLC, isr);
|
_xt_isr_attach(INUM_SLC, isr, arg);
|
||||||
SET_MASK_BITS(SLC.INT_ENABLE, SLC_INT_ENABLE_RX_EOF);
|
SET_MASK_BITS(SLC.INT_ENABLE, SLC_INT_ENABLE_RX_EOF);
|
||||||
SLC.INT_CLEAR = 0xFFFFFFFF;
|
SLC.INT_CLEAR = 0xFFFFFFFF;
|
||||||
_xt_isr_unmask(1<<INUM_SLC);
|
_xt_isr_unmask(1<<INUM_SLC);
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef void (*i2s_dma_isr_t)(void);
|
typedef void (*i2s_dma_isr_t)(void *);
|
||||||
|
|
||||||
typedef struct dma_descriptor {
|
typedef struct dma_descriptor {
|
||||||
uint32_t blocksize:12;
|
uint32_t blocksize:12;
|
||||||
|
@ -61,10 +61,11 @@ typedef struct {
|
||||||
* Initialize I2S and DMA subsystems.
|
* Initialize I2S and DMA subsystems.
|
||||||
*
|
*
|
||||||
* @param isr ISR handler. Can be NULL if interrupt handling is not needed.
|
* @param isr ISR handler. Can be NULL if interrupt handling is not needed.
|
||||||
|
* @param arg ISR handler arg.
|
||||||
* @param clock_div I2S clock configuration.
|
* @param clock_div I2S clock configuration.
|
||||||
* @param pins I2S pin configuration. Specifies which pins are enabled in I2S.
|
* @param pins I2S pin configuration. Specifies which pins are enabled in I2S.
|
||||||
*/
|
*/
|
||||||
void i2s_dma_init(i2s_dma_isr_t isr, i2s_clock_div_t clock_div, i2s_pins_t pins);
|
void i2s_dma_init(i2s_dma_isr_t isr, void *arg, i2s_clock_div_t clock_div, i2s_pins_t pins);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate I2S dividers for the specified frequency.
|
* Calculate I2S dividers for the specified frequency.
|
||||||
|
|
|
@ -43,7 +43,7 @@ typedef struct pwmInfoDefinition
|
||||||
|
|
||||||
static PWMInfo pwmInfo;
|
static PWMInfo pwmInfo;
|
||||||
|
|
||||||
static void frc1_interrupt_handler(void)
|
static void frc1_interrupt_handler(void *arg)
|
||||||
{
|
{
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
bool out = true;
|
bool out = true;
|
||||||
|
@ -97,7 +97,7 @@ void pwm_init(uint8_t npins, const uint8_t* pins)
|
||||||
pwm_stop();
|
pwm_stop();
|
||||||
|
|
||||||
/* set up ISRs */
|
/* set up ISRs */
|
||||||
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
|
_xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
|
||||||
|
|
||||||
/* Flag not running */
|
/* Flag not running */
|
||||||
pwmInfo.running = 0;
|
pwmInfo.running = 0;
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
|
|
||||||
#include "sntp.h"
|
#include "sntp.h"
|
||||||
|
|
||||||
#include "lwip/timers.h"
|
#include "lwip/timeouts.h"
|
||||||
#include "lwip/udp.h"
|
#include "lwip/udp.h"
|
||||||
#include "lwip/dns.h"
|
#include "lwip/dns.h"
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
|
@ -136,12 +136,12 @@
|
||||||
#define SNTP_STARTUP_DELAY 0
|
#define SNTP_STARTUP_DELAY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** SNTP receive timeout - in milliseconds
|
/** SNTP receive timeout - in seconds
|
||||||
* Also used as retry timeout - this shouldn't be too low.
|
* Also used as retry timeout - this shouldn't be too low.
|
||||||
* Default is 3 seconds.
|
* Default is 3 seconds.
|
||||||
*/
|
*/
|
||||||
#ifndef SNTP_RECV_TIMEOUT
|
#ifndef SNTP_RECV_TIMEOUT
|
||||||
#define SNTP_RECV_TIMEOUT 3000
|
#define SNTP_RECV_TIMEOUT 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** SNTP update delay - in milliseconds
|
/** SNTP update delay - in milliseconds
|
||||||
|
@ -384,8 +384,8 @@ sntp_request(void *arg)
|
||||||
/* bind to local address */
|
/* bind to local address */
|
||||||
if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) {
|
if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) {
|
||||||
/* set recv timeout */
|
/* set recv timeout */
|
||||||
timeout = SNTP_RECV_TIMEOUT;
|
const struct timeval timeout = { SNTP_RECV_TIMEOUT, 0 };
|
||||||
lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout));
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||||
|
|
||||||
/* prepare SNTP request */
|
/* prepare SNTP request */
|
||||||
sntp_initialize_request(&sntpmsg);
|
sntp_initialize_request(&sntpmsg);
|
||||||
|
@ -511,7 +511,7 @@ sntp_try_next_server(void* arg)
|
||||||
|
|
||||||
/** UDP recv callback for the sntp pcb */
|
/** UDP recv callback for the sntp pcb */
|
||||||
static void
|
static void
|
||||||
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
|
sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
|
||||||
{
|
{
|
||||||
u8_t mode;
|
u8_t mode;
|
||||||
u8_t stratum;
|
u8_t stratum;
|
||||||
|
@ -597,7 +597,7 @@ sntp_recv(void *arg, struct udp_pcb* pcb, struct pbuf *p, ip_addr_t *addr, u16_t
|
||||||
* @param server_addr resolved IP address of the SNTP server
|
* @param server_addr resolved IP address of the SNTP server
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sntp_send_request(ip_addr_t *server_addr)
|
sntp_send_request(const ip_addr_t *server_addr)
|
||||||
{
|
{
|
||||||
struct pbuf* p;
|
struct pbuf* p;
|
||||||
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
p = pbuf_alloc(PBUF_TRANSPORT, SNTP_MSG_LEN, PBUF_RAM);
|
||||||
|
@ -611,7 +611,7 @@ sntp_send_request(ip_addr_t *server_addr)
|
||||||
pbuf_free(p);
|
pbuf_free(p);
|
||||||
|
|
||||||
/* set up receive timeout: try next server or retry on timeout */
|
/* set up receive timeout: try next server or retry on timeout */
|
||||||
sys_timeout((u32_t)SNTP_RECV_TIMEOUT, sntp_try_next_server, NULL);
|
sys_timeout((u32_t)SNTP_RECV_TIMEOUT * 1000, sntp_try_next_server, NULL);
|
||||||
#if SNTP_CHECK_RESPONSE >= 1
|
#if SNTP_CHECK_RESPONSE >= 1
|
||||||
/* save server address to verify it in sntp_recv */
|
/* save server address to verify it in sntp_recv */
|
||||||
ip_addr_set(&sntp_last_server_address, server_addr);
|
ip_addr_set(&sntp_last_server_address, server_addr);
|
||||||
|
@ -629,7 +629,7 @@ sntp_send_request(ip_addr_t *server_addr)
|
||||||
* DNS found callback when using DNS names as server address.
|
* DNS found callback when using DNS names as server address.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
sntp_dns_found(const char* hostname, ip_addr_t *ipaddr, void *arg)
|
sntp_dns_found(const char* hostname, const ip_addr_t *ipaddr, void *arg)
|
||||||
{
|
{
|
||||||
LWIP_UNUSED_ARG(hostname);
|
LWIP_UNUSED_ARG(hostname);
|
||||||
LWIP_UNUSED_ARG(arg);
|
LWIP_UNUSED_ARG(arg);
|
||||||
|
|
|
@ -102,7 +102,7 @@ void sntp_update_rtc(time_t t, uint32_t us) {
|
||||||
// DEBUG: Compute and print drift
|
// DEBUG: Compute and print drift
|
||||||
int64_t sntp_current = sntp_base + TIMER_COUNT - tim_ref;
|
int64_t sntp_current = sntp_base + TIMER_COUNT - tim_ref;
|
||||||
int64_t sntp_correct = (((uint64_t)us + (uint64_t)t * 1000000U)<<12) / cal;
|
int64_t sntp_correct = (((uint64_t)us + (uint64_t)t * 1000000U)<<12) / cal;
|
||||||
printf("\nRTC Adjust: drift = %ld ticks, cal = %d\n", (time_t)(sntp_correct - sntp_current), cal);
|
printf("\nRTC Adjust: drift = %lld ticks, cal = %d\n", (time_t)(sntp_correct - sntp_current), (uint32_t)cal);
|
||||||
|
|
||||||
tim_ref = TIMER_COUNT;
|
tim_ref = TIMER_COUNT;
|
||||||
cal = sdk_system_rtc_clock_cali_proc();
|
cal = sdk_system_rtc_clock_cali_proc();
|
||||||
|
|
|
@ -44,7 +44,7 @@ static SemaphoreHandle_t uart0_sem = NULL;
|
||||||
static bool inited = false;
|
static bool inited = false;
|
||||||
static void uart0_rx_init(void);
|
static void uart0_rx_init(void);
|
||||||
|
|
||||||
IRAM void uart0_rx_handler(void)
|
IRAM void uart0_rx_handler(void *arg)
|
||||||
{
|
{
|
||||||
// TODO: Handle UART1, see reg 0x3ff20020, bit2, bit0 represents uart1 and uart0 respectively
|
// TODO: Handle UART1, see reg 0x3ff20020, bit2, bit0 represents uart1 and uart0 respectively
|
||||||
if (!UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
|
if (!UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) {
|
||||||
|
@ -97,7 +97,7 @@ static void uart0_rx_init(void)
|
||||||
int trig_lvl = 1;
|
int trig_lvl = 1;
|
||||||
uart0_sem = xSemaphoreCreateCounting(UART0_RX_SIZE, 0);
|
uart0_sem = xSemaphoreCreateCounting(UART0_RX_SIZE, 0);
|
||||||
|
|
||||||
_xt_isr_attach(INUM_UART, uart0_rx_handler);
|
_xt_isr_attach(INUM_UART, uart0_rx_handler, NULL);
|
||||||
_xt_isr_unmask(1 << INUM_UART);
|
_xt_isr_unmask(1 << INUM_UART);
|
||||||
|
|
||||||
// reset the rx fifo
|
// reset the rx fifo
|
||||||
|
|
10
extras/wificfg/component.mk
Normal file
10
extras/wificfg/component.mk
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# Component makefile for extras/wificfg
|
||||||
|
|
||||||
|
# Expected anyone using wificfg includes it as 'wificfg/wificfg.h'
|
||||||
|
INC_DIRS += $(wificfg_ROOT)..
|
||||||
|
|
||||||
|
# args for passing into compile rule generation
|
||||||
|
wificfg_INC_DIR =
|
||||||
|
wificfg_SRC_DIR = $(wificfg_ROOT)
|
||||||
|
|
||||||
|
$(eval $(call component_compile_rules,wificfg))
|
30
extras/wificfg/content/challenge.html
Normal file
30
extras/wificfg/content/challenge.html
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
"<!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><a href=\"/\">Home</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<form action=\"/challenge.html\" method=\"post\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Unlock the configuration interface</legend>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"pw\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||||
|
"placeholder=\"unlock-password\" value=\"\"></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<center><input type=\"submit\" value=\"Unlock\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"</form>"
|
||||||
|
"</body></html>"
|
11
extras/wificfg/content/favicon.ico
Normal file
11
extras/wificfg/content/favicon.ico
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
"HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: image/svg+xml\r\n"
|
||||||
|
"Cache-Control: max-age=900\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n",
|
||||||
|
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
|
||||||
|
"<svg xmlns:svg=\"http://www.w3.org/2000/svg\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 48 48\" version=\"1.1\">"
|
||||||
|
"<defs><linearGradient id=\"g1\" y2=\"248.63\" gradientUnits=\"userSpaceOnUse\" x2=\"153\" gradientTransform=\"matrix(.20068 0 0 .20068 -54.336 -1.0508)\" y1=\"15.424\" x1=\"99.777\"><stop style=\"stop-color:#0088FF\" offset=\"0\"/><stop style=\"stop-color:#b2dbff\" offset=\"1\"/></linearGradient></defs>"
|
||||||
|
"<path style=\"stroke-linejoin:round;color:#000000;stroke:#aaaaaa;stroke-linecap:round;fill:url(#g1)\" d=\"m22.7 0.94747c-0.474 0.03238-0.934 0.10563-1.398 0.15883h-0.032l-1.112 6.068c-1.812 0.4127-3.517 1.1132-5.051 2.065l-4.988-3.59c-1.3485 1.0468-2.5754 2.2677-3.6536 3.59l3.4628 5.0517c-1.0514 1.606-1.842 3.441-2.2874 5.369v0.031l-6.0361 0.953c-0.1104 0.902-0.1589 1.833-0.1589 2.764 0 0.762 0.021 1.514 0.0953 2.256l6.0362 1.08c0.4293 2.096 1.2448 4.054 2.3827 5.782l-3.5899 4.924c1.0281 1.277 2.2151 2.439 3.4946 3.463l5.0833-3.494c1.776 1.133 3.759 1.928 5.909 2.319l0.953 6.004c0.677 0.062 1.372 0.064 2.065 0.064 0.979 0 1.914-0.037 2.859-0.159l1.144-6.132c2.041-0.507 3.958-1.389 5.623-2.573l4.893 3.558c1.268-1.079 2.429-2.32 3.431-3.653l-3.558-5.147c0.963-1.664 1.631-3.5 1.969-5.464l6.005-0.953c0.052-0.627 0.063-1.234 0.063-1.875 0-1.112-0.129-2.203-0.286-3.272l-6.099-1.112c-0.478-1.765-1.263-3.412-2.256-4.892l3.59-4.9245c-1.113-1.3608-2.382-2.618-3.781-3.6852l-5.178 3.5581c-1.488-0.8802-3.09-1.5556-4.829-1.9379l-0.953-6.0362c-0.868-0.102-1.742-0.15883-2.637-0.15883-0.242 0-0.491-0.00761-0.731 0-0.117 0.00371-0.232-0.00681-0.349 0-0.032 0.00184-0.064-0.00216-0.095 0zm0.826 15.44c0.116-0.006 0.231 0 0.349 0 3.761 0 6.83 3.07 6.83 6.831 0 3.76-3.069 6.798-6.83 6.798s-6.799-3.038-6.799-6.798c0-3.643 2.852-6.648 6.45-6.831z\"/>"
|
||||||
|
"</svg>"
|
8
extras/wificfg/content/script.js
Normal file
8
extras/wificfg/content/script.js
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
"HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: text/javascript\r\n"
|
||||||
|
"Cache-Control: max-age=900\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"Connection: close\r\n"
|
||||||
|
"\r\n",
|
||||||
|
"function myFunction() { var x = document.getElementById(\"myTopnav\");"
|
||||||
|
"if (x.className === \"topnav\") { x.className += \" responsive\"; } else { x.className = \"topnav\"; } }"
|
19
extras/wificfg/content/style.css
Normal file
19
extras/wificfg/content/style.css
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
"HTTP/1.1 200 \r\n"
|
||||||
|
"Content-Type: text/css\r\n"
|
||||||
|
"Cache-Control: max-age=900\r\n"
|
||||||
|
"Transfer-Encoding: chunked\r\n"
|
||||||
|
"\r\n",
|
||||||
|
".dlh dd,h1{font-weight:300}.dlh{font-size:0;text-align:center}"
|
||||||
|
".dlh dd,.dlh dt{width:48%;width:calc(50% - 10px);margin:8px 0;display:inline-block;font-size:16px;vertical-align:middle}"
|
||||||
|
".dlh dt{text-align:right;padding-right:10px}"
|
||||||
|
".dlh dd{font-size:18px;text-align:left;padding-left:10px}"
|
||||||
|
"ul.topnav{list-style-type:none;margin:0;padding:0;overflow:hidden;background-color:#bbb}"
|
||||||
|
"ul.topnav li{float:left}"
|
||||||
|
"ul.topnav li a{display:inline-block;color:#444;text-align:center;padding:14px 16px;text-decoration:none;transition:.3s;font-size:17px}"
|
||||||
|
"ul.topnav li a:hover{background-color:#ddd}ul.topnav li.icon{display:none}"
|
||||||
|
"@media screen and (max-width:680px){ul.topnav li:not(.active){display:none}ul.topnav li.icon{float:right;display:inline-block}ul.topnav.responsive{position:relative}ul.topnav.responsive li.icon{position:absolute;right:0;top:0}ul.topnav.responsive li{float:none;display:inline}ul.topnav.responsive li a{display:block;text-align:left}}"
|
||||||
|
"html{min-height:100%}"
|
||||||
|
"body{background:#d0e4f7;background:-moz-linear-gradient(top, #d0e4f7 0%, #73b1e7 24%, #0a77d5 50%, #539fe1 79%, #87bcea 100%);background:-webkit-linear-gradient(top, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);background:linear-gradient(to bottom, #d0e4f7 0%,#73b1e7 24%,#0a77d5 50%,#539fe1 79%,#87bcea 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d0e4f7', endColorstr='#87bcea',GradientType=0)}"
|
||||||
|
"body{font-family:helvetica,arial,sans-serif;font-size:16px}"
|
||||||
|
"h1{font-size:26px}"
|
||||||
|
"p{font-size:14px}"
|
18
extras/wificfg/content/tasks.html
Normal file
18
extras/wificfg/content/tasks.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><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/tasks.html\">Tasks</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>",
|
||||||
|
"</body></html>"
|
90
extras/wificfg/content/wificfg/ap.html
Normal file
90
extras/wificfg/content/wificfg/ap.html
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
"<!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><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<form action=\"/wificfg/ap.html\" method=\"post\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>WiFi Access Point configuration</legend>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"enable\">Enable AP mode</label></dt>"
|
||||||
|
"<dd><input id=\"enable\" type=\"checkbox\" name=\"ap_enable\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"disable_if_sta\">Auto disable if station connection</label></dt>"
|
||||||
|
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_disable_if_sta\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||||
|
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||||
|
"name=\"ap_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||||
|
"\"/></dd>"
|
||||||
|
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||||
|
"<dd><input id=\"ssid\" type=\"text\" minlength=\"1\" maxlength=\"31\" name=\"ap_ssid\" "
|
||||||
|
"placeholder=\"my access point\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"ap\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"ap\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"ap_password\" "
|
||||||
|
"placeholder=\"password\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"hidden\">SSID Hidden</label></dt>"
|
||||||
|
"<dd><input id=\"hidden\" type=\"checkbox\" name=\"ap_ssid_hidden\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"ch\">Channel</label></dt>"
|
||||||
|
"<dd><input id=\"ch\" type=\"number\" size=\"2\" min=\"1\" max=\"14\" step=\"1\" "
|
||||||
|
"name=\"ap_channel\" placeholder=\"6\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"am\">Authentication Mode</label></dt>"
|
||||||
|
"<dd><select id=\"am\" name=\"ap_authmode\">"
|
||||||
|
"<option value=\"0\"",
|
||||||
|
">Open</option>"
|
||||||
|
"<option value=\"1\"",
|
||||||
|
">WEP</option>"
|
||||||
|
"<option value=\"2\"",
|
||||||
|
">WPA_PSK</option>"
|
||||||
|
"<option value=\"3\"",
|
||||||
|
">WPA2_PSK</option>"
|
||||||
|
"<option value=\"4\"",
|
||||||
|
">WPA_WPA2_PSK</option></select></dd>"
|
||||||
|
"<dt><label for=\"mc\">Max connections</label></dt>"
|
||||||
|
"<dd><input id=\"mc\" type=\"number\" size=\"2\" min=\"1\" max=\"8\" step=\"1\" "
|
||||||
|
"name=\"ap_max_conn\" placeholder=\"3\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"bi\">Beacon interval</label></dt>"
|
||||||
|
"<dd><input id=\"bi\" type=\"number\" size=\"6\" min=\"0\" max=\"10000\" step=\"1\" "
|
||||||
|
"name=\"ap_beacon_interval\" placeholder=\"100\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"ip\">IP Address</label></dt>"
|
||||||
|
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"ap_ip_addr\" placeholder=\"192.168.4.1\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"nm\">Netmask</label></dt>"
|
||||||
|
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"ap_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"dhcp\">DHCP Server Max Leases</label></dt>"
|
||||||
|
"<dd><input id=\"dhcp\" type=\"number\" size=\"2\" min=\"0\" max=\"16\" step=\"1\" "
|
||||||
|
"name=\"ap_dhcp_leases\" placeholder=\"4\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"dns_en\">DNS enabled</label></dt>"
|
||||||
|
"<dd><input id=\"dns_en\" type=\"checkbox\" name=\"ap_dns\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"<input type=\"hidden\" name=\"done\">"
|
||||||
|
"</form>"
|
||||||
|
"</body></html>"
|
52
extras/wificfg/content/wificfg/index.html
Normal file
52
extras/wificfg/content/wificfg/index.html
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
"<!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><a href=\"/\">Home</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<h1>WiFi Status</h1>"
|
||||||
|
"<dl class=\"dlh\">",
|
||||||
|
"</dl>"
|
||||||
|
"<br>"
|
||||||
|
"<form action=\"/wificfg/\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to lock the configuration interface, and have you noted the password?');\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Lock the configuration interface</legend>"
|
||||||
|
"<p>These WiFi configuration pages can be disabled for security on a shared network. If a password is supplied then they can be unlocked. Warning: if no password is supplied then it will not be possible to unlock these pages via this interface.</p>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"pw\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"pw\" type=\"text\" maxlength=\"32\" name=\"cfg_password\" "
|
||||||
|
"placeholder=\"unlock-password\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<input type=\"hidden\" name=\"cfg_enable\" value=\"0\">"
|
||||||
|
"<center><input type=\"submit\" value=\"Lock\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"</form>"
|
||||||
|
"<form action=\"/wificfg/restart.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to restart the device?');\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Restart device</legend>"
|
||||||
|
"<p>A restart is necessary for some changes to take effect.</p>"
|
||||||
|
"<center><button>Restart</button></center>"
|
||||||
|
"</fieldset></form>"
|
||||||
|
"<form action=\"/wificfg/erase.html\" method=\"post\" onsubmit=\"return confirm('Are you sure you want to erase the configuration?');\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>Erase configuration</legend>"
|
||||||
|
"<p>Erases the device configuration stored in the flash memory and restarts the device. "
|
||||||
|
"This might be useful to clear stored passwords and private configuration information."
|
||||||
|
"</p>"
|
||||||
|
"<center><button>Erase Configuration</button></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"</form>",
|
||||||
|
"</body></html>"
|
68
extras/wificfg/content/wificfg/sta.html
Normal file
68
extras/wificfg/content/wificfg/sta.html
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
"<!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><a href=\"/\">Home</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/\">WiFi Config</a></li>"
|
||||||
|
"<li class=\"active\"><a href=\"/wificfg/sta.html\">WiFi Station</a></li>"
|
||||||
|
"<li><a href=\"/wificfg/ap.html\">WiFi Access Point</a></li>"
|
||||||
|
"<li class=\"icon\">"
|
||||||
|
"<a href=\"javascript:void(0);\" onclick=\"myFunction()\">☰</a>"
|
||||||
|
"</li>"
|
||||||
|
"</ul>"
|
||||||
|
"<form action=\"/wificfg/sta.html\" method=\"post\">"
|
||||||
|
"<fieldset>"
|
||||||
|
"<legend>WiFi Station configuration</legend>"
|
||||||
|
"<dl class=\"dlh\">"
|
||||||
|
"<dt><label for=\"enable\">Enable Station mode</label></dt>"
|
||||||
|
"<dd><input id=\"enable\" type=\"checkbox\" name=\"sta_enable\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"disabled_restarts\">Disabled restarts</label></dt>"
|
||||||
|
"<dd><input id=\"disabled_restarts\" type=\"number\" size=\"2\" min=\"0\" step=\"1\" "
|
||||||
|
"name=\"sta_disabled_restarts\" placeholder=\"0\" value=\"",
|
||||||
|
"\" /></dd>"
|
||||||
|
"<dt><label for=\"ssid\">SSID</label></dt>"
|
||||||
|
"<dd><input id=\"ssid\" minlength=\"1\" maxlength=\"31\" type=\"text\" name=\"sta_ssid\" "
|
||||||
|
"placeholder=\"my access point\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"pw\">Password</label></dt>"
|
||||||
|
"<dd><input id=\"pw\" type=\"text\" minlength=\"8\" maxlength=\"63\" name=\"sta_password\" "
|
||||||
|
"placeholder=\"password\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"hostname\">Hostname</label></dt>"
|
||||||
|
"<dd><input id=\"hostname\" type=\"text\" maxlength=\"63\" name=\"hostname\" "
|
||||||
|
"placeholder=\"device-hostname\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"dhcp\">Enable DHCP</label></dt>"
|
||||||
|
"<dd><input id=\"dhcp\" type=\"radio\" name=\"sta_dhcp\" value=\"1\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"static\">Disable DHCP (static address below)</label></dt>"
|
||||||
|
"<dd><input id=\"static\" type=\"radio\" name=\"sta_dhcp\" value=\"0\" ",
|
||||||
|
" /></dd>"
|
||||||
|
"<dt><label for=\"ip\">Static IP Address</label></dt>"
|
||||||
|
"<dd><input id=\"ip\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"sta_ip_addr\" placeholder=\"192.168.1.50\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"nm\">Static Netmask</label></dt>"
|
||||||
|
"<dd><input id=\"nm\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"sta_netmask\" placeholder=\"255.255.255.0\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"<dt><label for=\"gw\">Static Gateway</label></dt>"
|
||||||
|
"<dd><input id=\"gw\" type=\"text\" maxlength=\"15\" size=\"15\" "
|
||||||
|
"pattern=\"(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)_*){3}\" "
|
||||||
|
"name=\"sta_gateway\" placeholder=\"192.168.1.1\" value=\"",
|
||||||
|
"\"></dd>"
|
||||||
|
"</dl>"
|
||||||
|
"<center><input type=\"reset\"> <input type=\"submit\" value=\"Save\"></center>"
|
||||||
|
"</fieldset>"
|
||||||
|
"<input type=\"hidden\" name=\"done\">"
|
||||||
|
"</form>"
|
||||||
|
"</body></html>"
|
2022
extras/wificfg/wificfg.c
Normal file
2022
extras/wificfg/wificfg.c
Normal file
File diff suppressed because it is too large
Load diff
137
extras/wificfg/wificfg.h
Normal file
137
extras/wificfg/wificfg.h
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
* WiFi configuration via a simple web server.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 OurAirQuality.org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0, January 2004 (the
|
||||||
|
* "License"); you may not use this file except in compliance with the
|
||||||
|
* License. You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/
|
||||||
|
*
|
||||||
|
* 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 CONTRIBUTORS 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 WITH THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __WIFICFG_H__
|
||||||
|
#define __WIFICFG_H__
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printf format used to initialize a default AP ssid. It is passed the last
|
||||||
|
* three bytes of the mac address. This may be NULL to not default the ssid,
|
||||||
|
* but the AP network will not run without a ssid.
|
||||||
|
*/
|
||||||
|
extern char *wificfg_default_ssid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A default password for the AP interface. This may be NULL to not default the
|
||||||
|
* password, but the AP network will not run without a password. The minimum
|
||||||
|
* length is 8 characters.
|
||||||
|
*/
|
||||||
|
extern char *wificfg_default_password;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A default hostname printf format string. This may be NULL to not default the
|
||||||
|
* hostname.
|
||||||
|
*/
|
||||||
|
extern char *wificfg_default_hostname;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The web server parses the http method string in these enums. The ANY method
|
||||||
|
* is only use for dispatch. The method enum is passed to the handler functions.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
HTTP_METHOD_GET,
|
||||||
|
HTTP_METHOD_POST,
|
||||||
|
HTTP_METHOD_HEAD,
|
||||||
|
HTTP_METHOD_OTHER,
|
||||||
|
HTTP_METHOD_ANY,
|
||||||
|
} wificfg_method;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The web server parses these content-type header values. This is passed to the
|
||||||
|
* dispatch function.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED,
|
||||||
|
HTTP_CONTENT_TYPE_OTHER
|
||||||
|
} wificfg_content_type;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The function signature for the http server request handler functions.
|
||||||
|
*
|
||||||
|
* The buffer, with its length, is usable by the handler.
|
||||||
|
*/
|
||||||
|
typedef int (* wificfg_handler)(int s, wificfg_method method,
|
||||||
|
uint32_t content_length,
|
||||||
|
wificfg_content_type content_type,
|
||||||
|
char *buf, size_t len);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *path;
|
||||||
|
wificfg_method method;
|
||||||
|
wificfg_handler handler;
|
||||||
|
bool secure;
|
||||||
|
} wificfg_dispatch;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start the Wifi Configuration http server task. The IP port number
|
||||||
|
* and a path dispatch list are needed. The dispatch list can not be
|
||||||
|
* stack allocated as it is passed to another task.
|
||||||
|
*/
|
||||||
|
void wificfg_init(uint32_t port, const wificfg_dispatch *dispatch);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Support for reading a form name or value from the socket. The name or value
|
||||||
|
* is truncated to the buffer length. The number of characters read is limited
|
||||||
|
* to the remainder which is updated. The 'valp' flag is set if a value follows.
|
||||||
|
*/
|
||||||
|
int wificfg_form_name_value(int s, bool *valp, size_t *rem, char *buf, size_t len);
|
||||||
|
|
||||||
|
/* Support for form url-encoding decoder. */
|
||||||
|
void wificfg_form_url_decode(char *string);
|
||||||
|
|
||||||
|
/* Support for html-escaping of form values. */
|
||||||
|
void wificfg_html_escape(char *string, char *buf, size_t len);
|
||||||
|
|
||||||
|
/* Support for writing a string in a response. */
|
||||||
|
int wificfg_write_string(int s, const char *str);
|
||||||
|
|
||||||
|
/* Support for writing a string in a response, with chunk transfer encoding.
|
||||||
|
* An optional buffer may be supplied to use to construct a chunk with the
|
||||||
|
* header and trailer, reducing the number of write() calls, and the str may be
|
||||||
|
* at the start of this buffer.
|
||||||
|
*/
|
||||||
|
int wificfg_write_string_chunk(int s, const char *str, char *buf, size_t len);
|
||||||
|
|
||||||
|
/* Write a chunk transfer encoding end marker. */
|
||||||
|
int wificfg_write_chunk_end(int s);
|
||||||
|
|
||||||
|
/* Write a chunk offset 4 bytes into the buffer. */
|
||||||
|
int wificfg_write_buffer_chunk(int s, char *buf);
|
||||||
|
|
||||||
|
/* Write a html title meta data, using the hostname or AP SSI. */
|
||||||
|
int wificfg_write_html_title(int s, char *buf, size_t len, const char *str);
|
||||||
|
|
||||||
|
/* Callback to notify the wificfg logic that a station connection has been
|
||||||
|
* successfully established. It might use this to disable the AP interface after
|
||||||
|
* a restart.
|
||||||
|
*/
|
||||||
|
void wificfg_got_sta_connect(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __WIFICFG_H__
|
|
@ -37,7 +37,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_DMA_BLOCK_SIZE 4095
|
#define MAX_DMA_BLOCK_SIZE 4095
|
||||||
#define DMA_PIXEL_SIZE 12 // each colour takes 4 bytes
|
// #define DMA_PIXEL_SIZE 16 // each colour takes 4 bytes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Amount of zero data to produce WS2812 reset condition.
|
* Amount of zero data to produce WS2812 reset condition.
|
||||||
|
@ -60,7 +60,7 @@ volatile uint32_t dma_isr_counter = 0;
|
||||||
|
|
||||||
static volatile bool i2s_dma_processing = false;
|
static volatile bool i2s_dma_processing = false;
|
||||||
|
|
||||||
static void dma_isr_handler(void)
|
static void dma_isr_handler(void *arg)
|
||||||
{
|
{
|
||||||
if (i2s_dma_is_eof_interrupt()) {
|
if (i2s_dma_is_eof_interrupt()) {
|
||||||
#ifdef WS2812_I2S_DEBUG
|
#ifdef WS2812_I2S_DEBUG
|
||||||
|
@ -117,9 +117,9 @@ static inline void init_descriptors_list(uint8_t *buf, uint32_t total_dma_data_s
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ws2812_i2s_init(uint32_t pixels_number)
|
void ws2812_i2s_init(uint32_t pixels_number, pixeltype_t type)
|
||||||
{
|
{
|
||||||
dma_buffer_size = pixels_number * DMA_PIXEL_SIZE;
|
dma_buffer_size = pixels_number * type;
|
||||||
dma_block_list_size = dma_buffer_size / MAX_DMA_BLOCK_SIZE;
|
dma_block_list_size = dma_buffer_size / MAX_DMA_BLOCK_SIZE;
|
||||||
|
|
||||||
if (dma_buffer_size % MAX_DMA_BLOCK_SIZE) {
|
if (dma_buffer_size % MAX_DMA_BLOCK_SIZE) {
|
||||||
|
@ -145,7 +145,7 @@ void ws2812_i2s_init(uint32_t pixels_number)
|
||||||
debug("i2s clock dividers, bclk=%d, clkm=%d\n",
|
debug("i2s clock dividers, bclk=%d, clkm=%d\n",
|
||||||
clock_div.bclk_div, clock_div.clkm_div);
|
clock_div.bclk_div, clock_div.clkm_div);
|
||||||
|
|
||||||
i2s_dma_init(dma_isr_handler, clock_div, i2s_pins);
|
i2s_dma_init(dma_isr_handler, NULL, clock_div, i2s_pins);
|
||||||
}
|
}
|
||||||
|
|
||||||
const IRAM_DATA int16_t bitpatterns[16] =
|
const IRAM_DATA int16_t bitpatterns[16] =
|
||||||
|
@ -156,13 +156,13 @@ const IRAM_DATA int16_t bitpatterns[16] =
|
||||||
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
|
0b1110111010001000, 0b1110111010001110, 0b1110111011101000, 0b1110111011101110,
|
||||||
};
|
};
|
||||||
|
|
||||||
void ws2812_i2s_update(ws2812_pixel_t *pixels)
|
void ws2812_i2s_update(ws2812_pixel_t *pixels, pixeltype_t type)
|
||||||
{
|
{
|
||||||
while (i2s_dma_processing) {};
|
while (i2s_dma_processing) {};
|
||||||
|
|
||||||
uint16_t *p_dma_buf = dma_buffer;
|
uint16_t *p_dma_buf = dma_buffer;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < (dma_buffer_size / DMA_PIXEL_SIZE); i++) {
|
for (uint32_t i = 0; i < (dma_buffer_size / type); i++) {
|
||||||
// green
|
// green
|
||||||
*p_dma_buf++ = bitpatterns[pixels[i].green & 0x0F];
|
*p_dma_buf++ = bitpatterns[pixels[i].green & 0x0F];
|
||||||
*p_dma_buf++ = bitpatterns[pixels[i].green >> 4];
|
*p_dma_buf++ = bitpatterns[pixels[i].green >> 4];
|
||||||
|
@ -174,6 +174,12 @@ void ws2812_i2s_update(ws2812_pixel_t *pixels)
|
||||||
// blue
|
// blue
|
||||||
*p_dma_buf++ = bitpatterns[pixels[i].blue & 0x0F];
|
*p_dma_buf++ = bitpatterns[pixels[i].blue & 0x0F];
|
||||||
*p_dma_buf++ = bitpatterns[pixels[i].blue >> 4];
|
*p_dma_buf++ = bitpatterns[pixels[i].blue >> 4];
|
||||||
|
|
||||||
|
if(type == PIXEL_RGBW) {
|
||||||
|
// white
|
||||||
|
*p_dma_buf++ = bitpatterns[pixels[i].white & 0x0F];
|
||||||
|
*p_dma_buf++ = bitpatterns[pixels[i].white >> 4];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i2s_dma_processing = true;
|
i2s_dma_processing = true;
|
||||||
|
|
|
@ -35,8 +35,14 @@ typedef struct {
|
||||||
uint8_t red;
|
uint8_t red;
|
||||||
uint8_t green;
|
uint8_t green;
|
||||||
uint8_t blue;
|
uint8_t blue;
|
||||||
|
uint8_t white;
|
||||||
} ws2812_pixel_t;
|
} ws2812_pixel_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PIXEL_RGB = 12,
|
||||||
|
PIXEL_RGBW = 16
|
||||||
|
} pixeltype_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize i2s and dma subsystems to work with ws2812 led strip.
|
* Initialize i2s and dma subsystems to work with ws2812 led strip.
|
||||||
*
|
*
|
||||||
|
@ -44,7 +50,7 @@ typedef struct {
|
||||||
*
|
*
|
||||||
* @param pixels_number Number of pixels in the strip.
|
* @param pixels_number Number of pixels in the strip.
|
||||||
*/
|
*/
|
||||||
void ws2812_i2s_init(uint32_t pixels_number);
|
void ws2812_i2s_init(uint32_t pixels_number, pixeltype_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update ws2812 pixels.
|
* Update ws2812 pixels.
|
||||||
|
@ -52,7 +58,7 @@ void ws2812_i2s_init(uint32_t pixels_number);
|
||||||
* @param pixels Array of 'pixels_number' pixels. The array must contain all
|
* @param pixels Array of 'pixels_number' pixels. The array must contain all
|
||||||
* the pixels.
|
* the pixels.
|
||||||
*/
|
*/
|
||||||
void ws2812_i2s_update(ws2812_pixel_t *pixels);
|
void ws2812_i2s_update(ws2812_pixel_t *pixels, pixeltype_t type);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,9 +44,9 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ip_info {
|
struct ip_info {
|
||||||
struct ip_addr ip;
|
struct ip4_addr ip;
|
||||||
struct ip_addr netmask;
|
struct ip4_addr netmask;
|
||||||
struct ip_addr gw;
|
struct ip4_addr gw;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool sdk_wifi_get_ip_info(uint8_t if_index, struct ip_info *info);
|
bool sdk_wifi_get_ip_info(uint8_t if_index, struct ip_info *info);
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct ip_addr;
|
struct ip4_addr;
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
* Defined in libmain.a
|
* Defined in libmain.a
|
||||||
|
@ -43,17 +43,6 @@ int sdk_uart_rx_one_char(char *buf);
|
||||||
*/
|
*/
|
||||||
void sdk_os_putc(char c);
|
void sdk_os_putc(char c);
|
||||||
|
|
||||||
/* Called when an IP gets set on the "station" (client) interface.
|
|
||||||
*/
|
|
||||||
void sdk_system_station_got_ip_set(struct ip_addr *ip_addr, struct ip_addr *sn_mask, struct ip_addr *gw_addr);
|
|
||||||
|
|
||||||
/* This is a no-op wrapper around ppRecycleRxPkt, which is defined in libpp.a
|
|
||||||
|
|
||||||
It's called when a pbuf is freed, and allows pp to reuse the 'eb' pointer to ESP-specific
|
|
||||||
pbuf data. (See esp-lwip pbuf.h)
|
|
||||||
*/
|
|
||||||
void sdk_system_pp_recycle_rx_pkt(void *eb);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -289,6 +289,7 @@ os_timer_disarm sdk_os_timer_disarm
|
||||||
os_timer_setfn sdk_os_timer_setfn
|
os_timer_setfn sdk_os_timer_setfn
|
||||||
os_update_cpu_frequency sdk_os_update_cpu_frequency
|
os_update_cpu_frequency sdk_os_update_cpu_frequency
|
||||||
pbkdf2_sha1 sdk_pbkdf2_sha1
|
pbkdf2_sha1 sdk_pbkdf2_sha1
|
||||||
|
pbuf_alloc sdk_pbuf_alloc
|
||||||
pbus_set_rxbbgain sdk_pbus_set_rxbbgain
|
pbus_set_rxbbgain sdk_pbus_set_rxbbgain
|
||||||
pend_flag_noise_check sdk_pend_flag_noise_check
|
pend_flag_noise_check sdk_pend_flag_noise_check
|
||||||
pend_flag_periodic_cal sdk_pend_flag_periodic_cal
|
pend_flag_periodic_cal sdk_pend_flag_periodic_cal
|
||||||
|
|
BIN
lib/libmain.a
BIN
lib/libmain.a
Binary file not shown.
|
@ -3,3 +3,4 @@ printf-stdarg.o
|
||||||
libc.o
|
libc.o
|
||||||
xtensa_vectors.o
|
xtensa_vectors.o
|
||||||
app_main.o
|
app_main.o
|
||||||
|
ets_timer.o
|
||||||
|
|
Binary file not shown.
BIN
lib/libpp.a
BIN
lib/libpp.a
Binary file not shown.
BIN
lib/libwpa.a
BIN
lib/libwpa.a
Binary file not shown.
|
@ -1,3 +1 @@
|
||||||
Newlib 2.2.0 with xtensa & locking patches, built from commit daa6ae40cdc8099f54c3e68a586fc1b906169c5a
|
Newlib from git://sourceware.org/git/newlib-cygwin.git with xtensa & locking patches see https://github.com/ourairquality/newlib and built from commit 7bcbbff5f7e3600806f352e88ec23ae0300edc29
|
||||||
|
|
||||||
For details on newlib in esp-open-rtos, see https://github.com/SuperHouse/esp-open-rtos/wiki/libc-configuration
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
12
libc/xtensa-lx106-elf/include/_newlib_version.h
Normal file
12
libc/xtensa-lx106-elf/include/_newlib_version.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/* _newlib_version.h. Generated from _newlib_version.hin by configure. */
|
||||||
|
/* Version macros for internal and downstream use. */
|
||||||
|
#ifndef _NEWLIB_VERSION_H__
|
||||||
|
#define _NEWLIB_VERSION_H__ 1
|
||||||
|
|
||||||
|
#define _NEWLIB_VERSION "2.5.0"
|
||||||
|
#define __NEWLIB__ 2
|
||||||
|
#define __NEWLIB_MINOR__ 5
|
||||||
|
#define __NEWLIB_PATCHLEVEL__ 0
|
||||||
|
|
||||||
|
#endif /* !_NEWLIB_VERSION_H__ */
|
||||||
|
|
|
@ -24,10 +24,12 @@ float complex cacosf(float complex);
|
||||||
/* 7.3.5.2 The casin functions */
|
/* 7.3.5.2 The casin functions */
|
||||||
double complex casin(double complex);
|
double complex casin(double complex);
|
||||||
float complex casinf(float complex);
|
float complex casinf(float complex);
|
||||||
|
long double complex casinl(long double complex);
|
||||||
|
|
||||||
/* 7.3.5.1 The catan functions */
|
/* 7.3.5.1 The catan functions */
|
||||||
double complex catan(double complex);
|
double complex catan(double complex);
|
||||||
float complex catanf(float complex);
|
float complex catanf(float complex);
|
||||||
|
long double complex catanl(long double complex);
|
||||||
|
|
||||||
/* 7.3.5.1 The ccos functions */
|
/* 7.3.5.1 The ccos functions */
|
||||||
double complex ccos(double complex);
|
double complex ccos(double complex);
|
||||||
|
@ -74,6 +76,7 @@ float complex cexpf(float complex);
|
||||||
/* 7.3.7.2 The clog functions */
|
/* 7.3.7.2 The clog functions */
|
||||||
double complex clog(double complex);
|
double complex clog(double complex);
|
||||||
float complex clogf(float complex);
|
float complex clogf(float complex);
|
||||||
|
long double complex clogl(long double complex);
|
||||||
|
|
||||||
/* 7.3.8 Power and absolute-value functions */
|
/* 7.3.8 Power and absolute-value functions */
|
||||||
/* 7.3.8.1 The cabs functions */
|
/* 7.3.8.1 The cabs functions */
|
||||||
|
@ -83,6 +86,7 @@ float complex clogf(float complex);
|
||||||
float cabsf(float complex) __RENAME(__c99_cabsf);
|
float cabsf(float complex) __RENAME(__c99_cabsf);
|
||||||
#endif
|
#endif
|
||||||
*/
|
*/
|
||||||
|
long double cabsl(long double complex) ;
|
||||||
double cabs(double complex) ;
|
double cabs(double complex) ;
|
||||||
float cabsf(float complex) ;
|
float cabsf(float complex) ;
|
||||||
|
|
||||||
|
@ -93,31 +97,56 @@ float complex cpowf(float complex, float complex);
|
||||||
/* 7.3.8.3 The csqrt functions */
|
/* 7.3.8.3 The csqrt functions */
|
||||||
double complex csqrt(double complex);
|
double complex csqrt(double complex);
|
||||||
float complex csqrtf(float complex);
|
float complex csqrtf(float complex);
|
||||||
|
long double complex csqrtl(long double complex);
|
||||||
|
|
||||||
/* 7.3.9 Manipulation functions */
|
/* 7.3.9 Manipulation functions */
|
||||||
/* 7.3.9.1 The carg functions */
|
/* 7.3.9.1 The carg functions */
|
||||||
double carg(double complex);
|
double carg(double complex);
|
||||||
float cargf(float complex);
|
float cargf(float complex);
|
||||||
|
long double cargl(long double complex);
|
||||||
|
|
||||||
/* 7.3.9.2 The cimag functions */
|
/* 7.3.9.2 The cimag functions */
|
||||||
double cimag(double complex);
|
double cimag(double complex);
|
||||||
float cimagf(float complex);
|
float cimagf(float complex);
|
||||||
/*long double cimagl(long double complex); */
|
long double cimagl(long double complex);
|
||||||
|
|
||||||
/* 7.3.9.3 The conj functions */
|
/* 7.3.9.3 The conj functions */
|
||||||
double complex conj(double complex);
|
double complex conj(double complex);
|
||||||
float complex conjf(float complex);
|
float complex conjf(float complex);
|
||||||
/*long double complex conjl(long double complex); */
|
|
||||||
|
|
||||||
/* 7.3.9.4 The cproj functions */
|
/* 7.3.9.4 The cproj functions */
|
||||||
double complex cproj(double complex);
|
double complex cproj(double complex);
|
||||||
float complex cprojf(float complex);
|
float complex cprojf(float complex);
|
||||||
/*long double complex cprojl(long double complex); */
|
|
||||||
|
|
||||||
/* 7.3.9.5 The creal functions */
|
/* 7.3.9.5 The creal functions */
|
||||||
double creal(double complex);
|
double creal(double complex);
|
||||||
float crealf(float complex);
|
float crealf(float complex);
|
||||||
/*long double creall(long double complex); */
|
long double creall(long double complex);
|
||||||
|
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
double complex clog10(double complex);
|
||||||
|
float complex clog10f(float complex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__)
|
||||||
|
long double complex cacosl(long double complex);
|
||||||
|
long double complex ccosl(long double complex);
|
||||||
|
long double complex csinl(long double complex);
|
||||||
|
long double complex ctanl(long double complex);
|
||||||
|
long double complex cacoshl(long double complex);
|
||||||
|
long double complex casinhl(long double complex);
|
||||||
|
long double complex catanhl(long double complex);
|
||||||
|
long double complex ccoshl(long double complex);
|
||||||
|
long double complex csinhl(long double complex);
|
||||||
|
long double complex ctanhl(long double complex);
|
||||||
|
long double complex cexpl(long double complex);
|
||||||
|
long double complex cpowl(long double complex, long double complex);
|
||||||
|
long double complex conjl(long double complex);
|
||||||
|
long double complex cprojl(long double complex);
|
||||||
|
#if __GNU_VISIBLE
|
||||||
|
long double complex clog10l(long double complex);
|
||||||
|
#endif
|
||||||
|
#endif /* __CYGWIN__ */
|
||||||
|
|
||||||
__END_DECLS
|
__END_DECLS
|
||||||
|
|
||||||
|
|
30
libc/xtensa-lx106-elf/include/cpio.h
Normal file
30
libc/xtensa-lx106-elf/include/cpio.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* POSIX.1 symbolic constants for c_mode field of cpio archive format */
|
||||||
|
|
||||||
|
#ifndef _CPIO_H
|
||||||
|
#define _CPIO_H
|
||||||
|
|
||||||
|
#define C_IRUSR 0000400 /* Read by owner */
|
||||||
|
#define C_IWUSR 0000200 /* Write by owner */
|
||||||
|
#define C_IXUSR 0000100 /* Execute by owner */
|
||||||
|
#define C_IRGRP 0000040 /* Read by group */
|
||||||
|
#define C_IWGRP 0000020 /* Write by group */
|
||||||
|
#define C_IXGRP 0000010 /* Execute by group */
|
||||||
|
#define C_IROTH 0000004 /* Read by others */
|
||||||
|
#define C_IWOTH 0000002 /* Write by others */
|
||||||
|
#define C_IXOTH 0000001 /* Execute by others */
|
||||||
|
#define C_ISUID 0004000 /* Set user ID */
|
||||||
|
#define C_ISGID 0002000 /* Set group ID */
|
||||||
|
#define C_ISVTX 0001000 /* On directories, restricted deletion flag */
|
||||||
|
|
||||||
|
#define C_ISDIR 0040000 /* Directory */
|
||||||
|
#define C_ISFIFO 0010000 /* FIFO */
|
||||||
|
#define C_ISREG 0100000 /* Regular file */
|
||||||
|
#define C_ISBLK 0060000 /* Block special */
|
||||||
|
#define C_ISCHR 0020000 /* Character special */
|
||||||
|
#define C_ISCTG 0110000 /* Reserved */
|
||||||
|
#define C_ISLNK 0120000 /* Symbolic link */
|
||||||
|
#define C_ISSOCK 0140000 /* Socket */
|
||||||
|
|
||||||
|
#define MAGIC "070707"
|
||||||
|
|
||||||
|
#endif /* _CPIO_H */
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue