Merge branch 'master' into master

This commit is contained in:
Florian Eich 2017-10-13 15:31:07 +02:00 committed by GitHub
commit 2a0150cbbb
191 changed files with 11189 additions and 11970 deletions

2
.gitmodules vendored
View file

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

View file

@ -1,65 +1,61 @@
The FreeRTOS.org source code is licensed by the *modified* GNU General Public The FreeRTOS open source license covers the FreeRTOS source files,
License (GPL), text provided below. A special exception to the GPL is which are located in the /FreeRTOS/Source directory of the official FreeRTOS
included to allow you to distribute a combined work that includes FreeRTOS download. It also covers most of the source files in the demo application
without being obliged to provide the source code for any proprietary projects, which are located in the /FreeRTOS/Demo directory of the official
components. See the licensing section of http://www.FreeRTOS.org for full FreeRTOS download. The demo projects may also include third party software that
details. The exception text is also included at the bottom of this file. is not part of FreeRTOS and is licensed separately to FreeRTOS. Examples of
third party software includes header files provided by chip or tools vendors,
linker scripts, peripheral drivers, etc. All the software in subdirectories of
the /FreeRTOS directory is either open source or distributed with permission,
and is free for use. For the avoidance of doubt, refer to the comments at the
top of each source file.
The FreeRTOS download also includes demo application source code, some of ----------------------------------------------------------------------------
which is provided by third parties AND IS LICENSED SEPARATELY FROM FREERTOS.
For the avoidance of any doubt refer to the comment included at the top NOTE: The modification to the GPL is included to allow you to distribute a
of each source and header file for license and copyright information. combined work that includes FreeRTOS without being obliged to provide the source
code for proprietary components.
This is a list of files for which Real Time Engineers Ltd are not the ----------------------------------------------------------------------------
copyright owner and are NOT COVERED BY THE GPL.
Applying to FreeRTOS V8.2.3 up to the latest version, the FreeRTOS GPL Exception
Text follows:
Any FreeRTOS *source code*, whether modified or in it's original release form,
or whether in whole or in part, can only be distributed by you under the terms
of the GNU General Public License plus this exception. An independent module is
a module which is not derived from or based on FreeRTOS.
Clause 1:
Linking FreeRTOS with other modules is making a combined work based on FreeRTOS.
Thus, the terms and conditions of the GNU General Public License V2 cover the
whole combination.
As a special exception, the copyright holders of FreeRTOS give you permission to
link FreeRTOS with independent modules to produce a statically linked
executable, regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms and
conditions of the license of that module. An independent module is a module
which is not derived from or based on FreeRTOS.
Clause 2:
FreeRTOS may not be used for any competitive or comparative purpose, including
the publication of any form of run time or compile time metric, without the
express permission of Real Time Engineers Ltd. (this is the norm within the
industry and is intended to ensure information accuracy).
1) Various header files provided by silicon manufacturers and tool vendors
that define processor specific memory addresses and utility macros.
Permission has been granted by the various copyright holders for these
files to be included in the FreeRTOS download. Users must ensure license
conditions are adhered to for any use other than compilation of the
FreeRTOS demo applications.
2) The uIP TCP/IP stack the copyright of which is held by Adam Dunkels.
Users must ensure the open source license conditions stated at the top
of each uIP source file is understood and adhered to.
3) The lwIP TCP/IP stack the copyright of which is held by the Swedish
Institute of Computer Science. Users must ensure the open source license
conditions stated at the top of each lwIP source file is understood and
adhered to.
4) Various peripheral driver source files and binaries provided by silicon
manufacturers and tool vendors. Permission has been granted by the
various copyright holders for these files to be included in the FreeRTOS
download. Users must ensure license conditions are adhered to for any
use other than compilation of the FreeRTOS demo applications.
5) The files contained within FreeRTOS\Demo\WizNET_DEMO_TERN_186\tern_code,
which are slightly modified versions of code provided by and copyright to
Tern Inc.
Errors and omissions should be reported to Richard Barry, contact details for
whom can be obtained from http://www.FreeRTOS.org.
The GPL license text follows.
A special exception to the GPL is included to allow you to distribute a
combined work that includes FreeRTOS without being obliged to provide
the source code for any proprietary components. See the licensing section
of http://www.FreeRTOS.org for full details. The exception text is also
included at the bottom of this file.
-------------------------------------------------------------------- --------------------------------------------------------------------
The standard GPL V2 text:
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
@ -401,40 +397,3 @@ consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General library. If this is what you want to do, use the GNU Library General
Public License instead of this License. Public License instead of this License.
----------------------------------------------------------------------------
The FreeRTOS GPL Exception Text:
Any FreeRTOS source code, whether modified or in it's original release form,
or whether in whole or in part, can only be distributed by you under the terms
of the GNU General Public License plus this exception. An independent module is
a module which is not derived from or based on FreeRTOS.
Clause 1:
Linking FreeRTOS statically or dynamically with other modules is making a
combined work based on FreeRTOS. Thus, the terms and conditions of the GNU
General Public License cover the whole combination.
As a special exception, the copyright holder of FreeRTOS gives you permission
to link FreeRTOS with independent modules that communicate with FreeRTOS
solely through the FreeRTOS API interface, regardless of the license terms of
these independent modules, and to copy and distribute the resulting combined
work under terms of your choice, provided that
+ Every copy of the combined work is accompanied by a written statement that
details to the recipient the version of FreeRTOS used and an offer by yourself
to provide the FreeRTOS source code (including any modifications you may have
made) should the recipient request it.
+ The combined work is not itself an RTOS, scheduler, kernel or related product.
+ The independent modules add significant and primary functionality to FreeRTOS
and do not merely extend the existing functionality already present in FreeRTOS.
Clause 2:
FreeRTOS may not be used for any competitive or comparative purpose, including the
publication of any form of run time or compile time metric, without the express
permission of Real Time Engineers Ltd. (this is the norm within the industry and
is intended to ensure information accuracy).

View file

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

View file

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

View file

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

View file

@ -1,15 +1,38 @@
/* Default esp-open-sdk FreeRTOSConfig file. /*
FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved
You can override settings in here by creating your own VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
FreeRTOSConfig.h file in your program directory.
You could just copy this file there and edit it, but it's This file is part of the FreeRTOS distribution.
recommended you instead define whatever you want to override and
then use #include_next<FreeRTOSConfig.h> to pick up these defaults.
The "blink" example in "examples/blink" provides an example of how FreeRTOS is free software; you can redistribute it and/or modify it under
to do this. the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
***************************************************************************
>>! NOTE: The modification to the GPL is included to allow you to !<<
>>! distribute a combined work that includes FreeRTOS without being !<<
>>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html
For esp-open-rtos, you can override settings in here by creating your own
FreeRTOSConfig.h file in your program directory. You could just copy this
file there and edit it, but it's recommended you instead define whatever you
want to override and then use #include_next<FreeRTOSConfig.h> to pick up
these defaults. The "blink" example in "examples/blink" provides an example
of how to do this.
1 tab == 4 spaces!
*/ */
#ifndef __DEFAULT_FREERTOS_CONFIG_H #ifndef __DEFAULT_FREERTOS_CONFIG_H
#define __DEFAULT_FREERTOS_CONFIG_H #define __DEFAULT_FREERTOS_CONFIG_H
@ -47,7 +70,7 @@
#define configTICK_RATE_HZ ( ( TickType_t ) 100 ) #define configTICK_RATE_HZ ( ( TickType_t ) 100 )
#endif #endif
#ifndef configMAX_PRIORITIES #ifndef configMAX_PRIORITIES
#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 15 ) #define configMAX_PRIORITIES ( 15 )
#endif #endif
#ifndef configMINIMAL_STACK_SIZE #ifndef configMINIMAL_STACK_SIZE
#define configMINIMAL_STACK_SIZE ( ( unsigned short )256 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short )256 )
@ -108,6 +131,10 @@
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#endif #endif
#ifndef configUSE_NEWLIB_REENTRANT
#define configUSE_NEWLIB_REENTRANT 1
#endif
/* Set the following definitions to 1 to include the API function, or zero /* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */ to exclude the API function. */
#ifndef INCLUDE_vTaskPrioritySet #ifndef INCLUDE_vTaskPrioritySet
@ -144,5 +171,10 @@ to exclude the API function. */
#define configENABLE_BACKWARD_COMPATIBILITY 0 #define configENABLE_BACKWARD_COMPATIBILITY 0
#endif #endif
/* Normal assert() semantics without relying on the provision of an assert.h
header file. */
void vAssertCalled(const char * pcFile, unsigned long ulLine);
#define configASSERT(x) if((x) == 0) vAssertCalled(__FILE__, __LINE__);
#endif /* __DEFAULT_FREERTOS_CONFIG_H */ #endif /* __DEFAULT_FREERTOS_CONFIG_H */

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -205,7 +205,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t;
typedef struct xLIST typedef struct xLIST
{ {
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
configLIST_VOLATILE UBaseType_t uxNumberOfItems; volatile UBaseType_t uxNumberOfItems;
ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -83,6 +83,7 @@
BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ); BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask );
TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer );
BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask );
void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions );
void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); void MPU_vTaskDelete( TaskHandle_t xTaskToDelete );
void MPU_vTaskDelay( const TickType_t xTicksToDelay ); void MPU_vTaskDelay( const TickType_t xTicksToDelay );
@ -124,7 +125,9 @@ BaseType_t MPU_xTaskGetSchedulerState( void );
/* MPU versions of queue.h API function. */ /* MPU versions of queue.h API function. */
BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition );
BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait );
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait );
UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue );
UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue );
void MPU_vQueueDelete( QueueHandle_t xQueue ); void MPU_vQueueDelete( QueueHandle_t xQueue );

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -328,7 +328,7 @@ typedef QueueHandle_t SemaphoreHandle_t;
* \defgroup xSemaphoreTake xSemaphoreTake * \defgroup xSemaphoreTake xSemaphoreTake
* \ingroup Semaphores * \ingroup Semaphores
*/ */
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) #define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
/** /**
* semphr. h * semphr. h
@ -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>

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -73,10 +73,12 @@
#include <malloc.h> #include <malloc.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <xtensa_ops.h> #include <xtensa_ops.h>
#include "FreeRTOS.h" #include "FreeRTOS.h"
#include "task.h" #include "task.h"
#include "queue.h"
#include "xtensa_rtos.h" #include "xtensa_rtos.h"
unsigned cpu_sr; unsigned cpu_sr;
@ -91,6 +93,13 @@ char level1_int_disabled;
*/ */
void *xPortSupervisorStackPointer; void *xPortSupervisorStackPointer;
void vAssertCalled(const char * pcFile, unsigned long ulLine)
{
printf("rtos assert %s %lu\n", pcFile, ulLine);
abort();
//for (;;);
}
/* /*
* Stack initialization * Stack initialization
*/ */
@ -100,7 +109,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
portSTACK_TYPE *sp, *tp; portSTACK_TYPE *sp, *tp;
/* Create interrupt stack frame aligned to 16 byte boundary */ /* Create interrupt stack frame aligned to 16 byte boundary */
sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack+1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf); sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack + 1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf);
/* Clear the entire frame (do not use memset() because we don't depend on C library) */ /* Clear the entire frame (do not use memset() because we don't depend on C library) */
for (tp = sp; tp <= pxTopOfStack; ++tp) for (tp = sp; tp <= pxTopOfStack; ++tp)
@ -121,30 +130,29 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
static int pending_soft_sv; static int pending_soft_sv;
static int pending_maclayer_sv; static int pending_maclayer_sv;
/* PendSV is called in place of vPortYield() to request a supervisor /*
call. * The portYIELD macro calls PendSV with SVC_Software to set a pending interrupt
* service callback that allows a task switch, and this occur when interrupts
The portYIELD macro calls pendSV if it's a software request. * are enabled which might be after exiting the critical region below.
*
The libpp and libudhcp libraries also call this function, assuming * The wdev NMI calls this function from pp_post() with SVC_MACLayer to set a
always with arg==2 (but maybe sometimes with arg==1?) * pending interrupt service callback which flushs the queue of messages that
* the NMI stashes away. This interrupt will be triggered after the return from
In the original esp_iot_rtos_sdk implementation, arg was a char. Using an * the NMI and when interrupts are enabled. The NMI can not touch the FreeRTOS
enum is ABI-compatible, though. * queues itself. The NMI must not touch the interrupt masks so that path must
*/ * not call vPortEnterCritical and vPortExitCritical.
*/
void IRAM PendSV(enum SVC_ReqType req) void IRAM PendSV(enum SVC_ReqType req)
{ {
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);
}

View file

@ -1,65 +1,29 @@
/* /*
FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
***************************************************************************
* *
* FreeRTOS provides completely free yet professionally developed, *
* robust, strictly quality controlled, supported, and cross *
* platform software that has become a de facto standard. *
* *
* Help yourself get started quickly and support the FreeRTOS *
* project by purchasing a FreeRTOS tutorial book, reference *
* manual, or both from: http://www.FreeRTOS.org/Documentation *
* *
* Thank you! *
* *
***************************************************************************
This file is part of the FreeRTOS distribution. This file is part of the FreeRTOS distribution.
FreeRTOS is free software; you can redistribute it and/or modify it under FreeRTOS is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License (version 2) as published by the the terms of the GNU General Public License (version 2) as published by the
Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
>>! NOTE: The modification to the GPL is included to allow you to distribute ***************************************************************************
>>! a combined work that includes FreeRTOS without being obliged to provide >>! NOTE: The modification to the GPL is included to allow you to !<<
>>! the source code for proprietary components outside of the FreeRTOS >>! distribute a combined work that includes FreeRTOS without being !<<
>>! kernel. >>! obliged to provide the source code for proprietary components !<<
>>! outside of the FreeRTOS kernel. !<<
***************************************************************************
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. Full license text is available from the following FOR A PARTICULAR PURPOSE. Full license text is available on the following
link: http://www.freertos.org/a00114.html link: http://www.freertos.org/a00114.html
1 tab == 4 spaces! 1 tab == 4 spaces!
***************************************************************************
* *
* Having a problem? Start by reading the FAQ "My application does *
* not run, what could be wrong?" *
* *
* http://www.FreeRTOS.org/FAQHelp.html *
* *
***************************************************************************
http://www.FreeRTOS.org - Documentation, books, training, latest versions,
license and Real Time Engineers Ltd. contact details.
http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
including FreeRTOS+Trace - an indispensable productivity tool, a DOS
compatible FAT file system, and our tiny thread aware UDP/IP stack.
http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
licenses offer ticketed support, indemnification and middleware.
http://www.SafeRTOS.com - High Integrity Systems also provide a safety
engineered and independently SIL3 certified version for use in safety and
mission critical applications that require provable dependability.
1 tab == 4 spaces!
*/ */
@ -92,16 +56,15 @@ extern "C" {
#define portDOUBLE double #define portDOUBLE double
#define portLONG long #define portLONG long
#define portSHORT short #define portSHORT short
#define portSTACK_TYPE unsigned portLONG #define portSTACK_TYPE uint32_t
#define portBASE_TYPE long #define portBASE_TYPE long
#define portPOINTER_SIZE_TYPE unsigned portLONG
typedef portSTACK_TYPE StackType_t; typedef portSTACK_TYPE StackType_t;
typedef portBASE_TYPE BaseType_t; typedef portBASE_TYPE BaseType_t;
typedef unsigned portBASE_TYPE UBaseType_t; typedef unsigned portBASE_TYPE UBaseType_t;
typedef uint32_t TickType_t; typedef uint32_t TickType_t;
#define portMAX_DELAY ( TickType_t ) 0xffffffff #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
/* Architecture specifics. */ /* Architecture specifics. */
#define portSTACK_GROWTH ( -1 ) #define portSTACK_GROWTH ( -1 )
@ -156,6 +119,9 @@ extern unsigned cpu_sr;
prefer to _xt_disable_interrupts & _xt_enable_interrupts and store prefer to _xt_disable_interrupts & _xt_enable_interrupts and store
the ps value in a local variable - that approach is recursive-safe the ps value in a local variable - that approach is recursive-safe
and generally better. and generally better.
The NMI must not touch the interrupt mask and it should not in
regular operation, but there is a guard here just in case.
*/ */
inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void) inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void)
{ {
@ -185,6 +151,10 @@ not necessary for to use this port. They are defined so the common demo files
(which build with all the ports) will build. */ (which build with all the ports) will build. */
#define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
#define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters ) #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
/* FreeRTOS API functions should not be called from the NMI handler. */
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT(sdk_NMIIrqIsOn == 0)
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#ifdef __cplusplus #ifdef __cplusplus

View file

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

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -255,6 +255,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION; static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
#endif #endif
#if( configUSE_MUTEXES == 1 )
/*
* If a task waiting for a mutex causes the mutex holder to inherit a
* priority, but the waiting task times out, then the holder should
* disinherit the priority - but only down to the highest priority of any
* other tasks that are waiting for the same mutex. This function returns
* that priority.
*/
static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
#endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
@ -374,6 +384,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
} }
else
{
traceQUEUE_CREATE_FAILED( ucQueueType );
}
return pxNewQueue; return pxNewQueue;
} }
@ -422,6 +436,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue ); prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
} }
else
{
traceQUEUE_CREATE_FAILED( ucQueueType );
}
return pxNewQueue; return pxNewQueue;
} }
@ -567,6 +585,32 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) )
void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore )
{
void *pxReturn;
configASSERT( xSemaphore );
/* Mutexes cannot be used in interrupt service routines, so the mutex
holder should not change in an ISR, and therefore a critical section is
not required here. */
if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX )
{
pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder;
}
else
{
pxReturn = NULL;
}
return pxReturn;
} /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */
#endif
/*-----------------------------------------------------------*/
#if ( configUSE_RECURSIVE_MUTEXES == 1 ) #if ( configUSE_RECURSIVE_MUTEXES == 1 )
BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
@ -643,7 +687,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
} }
else else
{ {
xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); xReturn = xQueueSemaphoreTake( pxMutex, xTicksToWait );
/* pdPASS will only be returned if the mutex was successfully /* pdPASS will only be returned if the mutex was successfully
obtained. The calling task may have entered the Blocked state obtained. The calling task may have entered the Blocked state
@ -855,7 +899,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
{ {
/* The queue was full and a block time was specified so /* The queue was full and a block time was specified so
configure the timeout structure. */ configure the timeout structure. */
vTaskSetTimeOutState( &xTimeOut ); vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE; xEntryTimeSet = pdTRUE;
} }
else else
@ -1127,7 +1171,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
can be assumed there is no mutex holder and no need to determine if can be assumed there is no mutex holder and no need to determine if
priority disinheritance is needed. Simply increase the count of priority disinheritance is needed. Simply increase the count of
messages (semaphores) available. */ messages (semaphores) available. */
pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
/* The event list is not altered if the queue is locked. This will /* The event list is not altered if the queue is locked. This will
be done when the queue is unlocked later. */ be done when the queue is unlocked later. */
@ -1234,21 +1278,27 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking ) BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
{ {
BaseType_t xEntryTimeSet = pdFALSE; BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut; TimeOut_t xTimeOut;
int8_t *pcOriginalReadPosition;
Queue_t * const pxQueue = ( Queue_t * ) xQueue; Queue_t * const pxQueue = ( Queue_t * ) xQueue;
configASSERT( pxQueue ); /* Check the pointer is not NULL. */
configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); configASSERT( ( pxQueue ) );
/* The buffer into which data is received can only be NULL if the data size
is zero (so no data is copied into the buffer. */
configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
/* Cannot block if the scheduler is suspended. */
#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
{ {
configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
} }
#endif #endif
/* This function relaxes the coding standard somewhat to allow return /* This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest statements within the function itself. This is done in the interest
of execution time efficiency. */ of execution time efficiency. */
@ -1263,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;
} }

View file

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

View file

@ -1,5 +1,5 @@
/* /*
FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
All rights reserved All rights reserved
VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@ -131,12 +131,23 @@ made to free the RAM that was allocated statically.
tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a
task to be created using either statically or dynamically allocated RAM. Note task to be created using either statically or dynamically allocated RAM. Note
that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
a statically allocated stack and a dynamically allocated TCB. */ a statically allocated stack and a dynamically allocated TCB.
#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) !!!NOTE!!! If the definition of tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is
changed then the definition of StaticTask_t must also be updated. */
#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
#define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 ) #define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
#define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 ) #define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
#define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 ) #define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
/* If any of the following are set then task stacks are filled with a known
value so the high water mark can be determined. If none of the following are
set then don't fill the stack so there is no unnecessary dependency on memset. */
#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
#else
#define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
#endif
/* /*
* Macros used by vListTask to indicate which state a task is in. * Macros used by vListTask to indicate which state a task is in.
*/ */
@ -153,6 +164,12 @@ a statically allocated stack and a dynamically allocated TCB. */
#define static #define static
#endif #endif
/* The name allocated to the Idle task. This can be overridden by defining
configIDLE_TASK_NAME in FreeRTOSConfig.h. */
#ifndef configIDLE_TASK_NAME
#define configIDLE_TASK_NAME "IDLE"
#endif
#if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is /* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
@ -304,8 +321,8 @@ typedef struct tskTaskControlBlock
StackType_t *pxStack; /*< Points to the start of the stack. */ StackType_t *pxStack; /*< Points to the start of the stack. */
char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
#if ( portSTACK_GROWTH > 0 ) #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t *pxEndOfStack; /*< Points to the end of the stack on architectures where the stack grows up from low memory. */ StackType_t *pxEndOfStack; /*< Points to the highest valid address for the stack. */
#endif #endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 ) #if ( portCRITICAL_NESTING_IN_TCB == 1 )
@ -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

View file

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

View file

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

View file

@ -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;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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;

View file

@ -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;
} }

View file

@ -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);
}
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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);
}

View file

@ -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");
} }
} }
} }

View file

@ -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)
{ {

View file

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

View file

@ -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__ */

View file

@ -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
View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1 @@
FLASH_SIZE ?= 32

View 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);
}

View file

@ -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);
} }

View file

@ -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;

View file

@ -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];

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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, &reg_addr, &data, 1); int err = i2c_slave_write(BUS, slave_addr, &reg_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, &reg_addr, &reg_data, 1); err = i2c_slave_read(BUS, slave_addr, &reg_addr, &reg_data, 1);
```` ```
For details please see `extras/i2c/i2c.h`. For details please see `extras/i2c/i2c.h`.

View file

@ -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;
} }

View file

@ -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.

View file

@ -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);

View file

@ -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.

View file

@ -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;

View file

@ -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);

View file

@ -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();

View file

@ -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

View 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))

View 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()\">&#9776;</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>"

View 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>"

View 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\"; } }"

View 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}"

View file

@ -0,0 +1,18 @@
"<!DOCTYPE html><html lang=\"en\">"
"<head>"
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/style.css\">"
"<script src=\"/script.js\"></script>"
"<title>",
"</title>"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
"</head>"
"<body>"
"<ul class=\"topnav\" id=\"myTopnav\">"
"<li><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()\">&#9776;</a>"
"</li>"
"</ul>",
"</body></html>"

View 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()\">&#9776;</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\">&nbsp;<input type=\"submit\" value=\"Save\"></center>"
"</fieldset>"
"<input type=\"hidden\" name=\"done\">"
"</form>"
"</body></html>"

View 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()\">&#9776;</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>"

View 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()\">&#9776;</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\">&nbsp;<input type=\"submit\" value=\"Save\"></center>"
"</fieldset>"
"<input type=\"hidden\" name=\"done\">"
"</form>"
"</body></html>"

2022
extras/wificfg/wificfg.c Normal file

File diff suppressed because it is too large Load diff

137
extras/wificfg/wificfg.h Normal file
View 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__

View file

@ -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;

View file

@ -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
} }

View file

@ -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);

View file

@ -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

View file

@ -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

Binary file not shown.

View file

@ -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.

Binary file not shown.

Binary file not shown.

View file

@ -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

View 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__ */

View file

@ -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

View 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