diff --git a/.gitmodules b/.gitmodules index 8fa55e5..52db9b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "lwip/lwip"] path = lwip/lwip - url = https://github.com/SuperHouse/esp-lwip.git + url = https://github.com/ourairquality/lwip.git [submodule "extras/mbedtls/mbedtls"] path = extras/mbedtls/mbedtls url = https://github.com/ARMmbed/mbedtls.git diff --git a/.travis.yml b/.travis.yml index c00c5d2..39674fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ language: c sudo: false env: # Target commit for https://github.com/pfalcon/esp-open-sdk/ - OPENSDK_COMMIT=a48b12f + OPENSDK_COMMIT=b069537 CROSS_ROOT="${HOME}/toolchain-${OPENSDK_COMMIT}" CROSS_BINDIR="${CROSS_ROOT}/bin" CROSS="ccache xtensa-lx106-elf-" @@ -29,12 +29,14 @@ addons: - libncurses5-dev - libexpat1-dev - python - - python-serial + - python-pip - sed - git + - help2man - vim-common before_install: + - pip install --user pyserial - travis_wait 30 utils/travis_build/install_toolchain.sh script: diff --git a/FreeRTOS/License/license.txt b/FreeRTOS/License/license.txt index e48ed80..5d243b8 100644 --- a/FreeRTOS/License/license.txt +++ b/FreeRTOS/License/license.txt @@ -1,65 +1,61 @@ -The FreeRTOS.org source code is licensed by the *modified* GNU General Public -License (GPL), text provided below. A special exception to the GPL is -included to allow you to distribute a combined work that includes FreeRTOS -without being obliged to provide the source code for any proprietary -components. See the licensing section of http://www.FreeRTOS.org for full -details. The exception text is also included at the bottom of this file. +The FreeRTOS open source license covers the FreeRTOS source files, +which are located in the /FreeRTOS/Source directory of the official FreeRTOS +download. It also covers most of the source files in the demo application +projects, which are located in the /FreeRTOS/Demo directory of the official +FreeRTOS download. The demo projects may also include third party software that +is not part of FreeRTOS and is licensed separately to FreeRTOS. Examples of +third party software includes header files provided by chip or tools vendors, +linker scripts, peripheral drivers, etc. All the software in subdirectories of +the /FreeRTOS directory is either open source or distributed with permission, +and is free for use. For the avoidance of doubt, refer to the comments at the +top of each source file. -The FreeRTOS download also includes demo application source code, some of -which is provided by third parties AND IS LICENSED SEPARATELY FROM FREERTOS. +---------------------------------------------------------------------------- -For the avoidance of any doubt refer to the comment included at the top -of each source and header file for license and copyright information. +NOTE: The modification to the GPL is included to allow you to distribute a +combined work that includes FreeRTOS without being obliged to provide the source +code for proprietary components. -This is a list of files for which Real Time Engineers Ltd are not the -copyright owner and are NOT COVERED BY THE GPL. +---------------------------------------------------------------------------- + +Applying to FreeRTOS V8.2.3 up to the latest version, the FreeRTOS GPL Exception +Text follows: + +Any FreeRTOS *source code*, whether modified or in it's original release form, +or whether in whole or in part, can only be distributed by you under the terms +of the GNU General Public License plus this exception. An independent module is +a module which is not derived from or based on FreeRTOS. + +Clause 1: + +Linking FreeRTOS with other modules is making a combined work based on FreeRTOS. +Thus, the terms and conditions of the GNU General Public License V2 cover the +whole combination. + +As a special exception, the copyright holders of FreeRTOS give you permission to +link FreeRTOS with independent modules to produce a statically linked +executable, regardless of the license terms of these independent modules, and to +copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms and +conditions of the license of that module. An independent module is a module +which is not derived from or based on FreeRTOS. + +Clause 2: + +FreeRTOS may not be used for any competitive or comparative purpose, including +the publication of any form of run time or compile time metric, without the +express permission of Real Time Engineers Ltd. (this is the norm within the +industry and is intended to ensure information accuracy). -1) Various header files provided by silicon manufacturers and tool vendors - that define processor specific memory addresses and utility macros. - Permission has been granted by the various copyright holders for these - files to be included in the FreeRTOS download. Users must ensure license - conditions are adhered to for any use other than compilation of the - FreeRTOS demo applications. - -2) The uIP TCP/IP stack the copyright of which is held by Adam Dunkels. - Users must ensure the open source license conditions stated at the top - of each uIP source file is understood and adhered to. - -3) The lwIP TCP/IP stack the copyright of which is held by the Swedish - Institute of Computer Science. Users must ensure the open source license - conditions stated at the top of each lwIP source file is understood and - adhered to. - -4) Various peripheral driver source files and binaries provided by silicon - manufacturers and tool vendors. Permission has been granted by the - various copyright holders for these files to be included in the FreeRTOS - download. Users must ensure license conditions are adhered to for any - use other than compilation of the FreeRTOS demo applications. - -5) The files contained within FreeRTOS\Demo\WizNET_DEMO_TERN_186\tern_code, - which are slightly modified versions of code provided by and copyright to - Tern Inc. - -Errors and omissions should be reported to Richard Barry, contact details for -whom can be obtained from http://www.FreeRTOS.org. - - - - - -The GPL license text follows. - -A special exception to the GPL is included to allow you to distribute a -combined work that includes FreeRTOS without being obliged to provide -the source code for any proprietary components. See the licensing section -of http://www.FreeRTOS.org for full details. The exception text is also -included at the bottom of this file. -------------------------------------------------------------------- +The standard GPL V2 text: + + GNU GENERAL PUBLIC LICENSE Version 2, June 1991 @@ -401,40 +397,3 @@ consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ----------------------------------------------------------------------------- - -The FreeRTOS GPL Exception Text: - -Any FreeRTOS source code, whether modified or in it's original release form, -or whether in whole or in part, can only be distributed by you under the terms -of the GNU General Public License plus this exception. An independent module is -a module which is not derived from or based on FreeRTOS. - -Clause 1: - -Linking FreeRTOS statically or dynamically with other modules is making a -combined work based on FreeRTOS. Thus, the terms and conditions of the GNU -General Public License cover the whole combination. - -As a special exception, the copyright holder of FreeRTOS gives you permission -to link FreeRTOS with independent modules that communicate with FreeRTOS -solely through the FreeRTOS API interface, regardless of the license terms of -these independent modules, and to copy and distribute the resulting combined -work under terms of your choice, provided that - - + Every copy of the combined work is accompanied by a written statement that - details to the recipient the version of FreeRTOS used and an offer by yourself - to provide the FreeRTOS source code (including any modifications you may have - made) should the recipient request it. - - + The combined work is not itself an RTOS, scheduler, kernel or related product. - - + The independent modules add significant and primary functionality to FreeRTOS - and do not merely extend the existing functionality already present in FreeRTOS. - -Clause 2: - -FreeRTOS may not be used for any competitive or comparative purpose, including the -publication of any form of run time or compile time metric, without the express -permission of Real Time Engineers Ltd. (this is the norm within the industry and -is intended to ensure information accuracy). diff --git a/FreeRTOS/Source/croutine.c b/FreeRTOS/Source/croutine.c index 993e09b..d3b0eff 100644 --- a/FreeRTOS/Source/croutine.c +++ b/FreeRTOS/Source/croutine.c @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/event_groups.c b/FreeRTOS/Source/event_groups.c index b8df5fd..4434bdf 100644 --- a/FreeRTOS/Source/event_groups.c +++ b/FreeRTOS/Source/event_groups.c @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -139,6 +139,16 @@ static BaseType_t prvTestWaitCondition( const EventBits_t uxCurrentEventBits, co /* A StaticEventGroup_t object must be provided. */ configASSERT( pxEventGroupBuffer ); + #if( configASSERT_DEFINED == 1 ) + { + /* Sanity check that the size of the structure used to declare a + variable of type StaticEventGroup_t equals the size of the real + event group structure. */ + volatile size_t xSize = sizeof( StaticEventGroup_t ); + configASSERT( xSize == sizeof( EventGroup_t ) ); + } + #endif /* configASSERT_DEFINED */ + /* The user has provided a statically allocated event group - use it. */ pxEventBits = ( EventGroup_t * ) pxEventGroupBuffer; /*lint !e740 EventGroup_t and StaticEventGroup_t are guaranteed to have the same size and alignment requirement - checked by configASSERT(). */ @@ -602,7 +612,7 @@ BaseType_t xMatchFound = pdFALSE; eventUNBLOCKED_DUE_TO_BIT_SET bit is set so the task knows that is was unblocked due to its required bits matching, rather than because it timed out. */ - ( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); + vTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET ); } /* Move onto the next list item. Note pxListItem->pxNext is not @@ -633,9 +643,9 @@ const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits ); while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 ) { /* Unblock the task, returning 0 as the event list is being deleted - and cannot therefore have any bits set. */ - configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); - ( void ) xTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); + and cannot therefore have any bits set. */ + configASSERT( pxTasksWaitingForBits->xListEnd.pxNext != ( const ListItem_t * ) &( pxTasksWaitingForBits->xListEnd ) ); + vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET ); } #if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) ) diff --git a/FreeRTOS/Source/include/FreeRTOS.h b/FreeRTOS/Source/include/FreeRTOS.h index 63a08b3..94ea1f8 100644 --- a/FreeRTOS/Source/include/FreeRTOS.h +++ b/FreeRTOS/Source/include/FreeRTOS.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -126,6 +126,10 @@ extern "C" { #error Missing definition: configMAX_PRIORITIES must be defined in FreeRTOSConfig.h. See the Configuration section of the FreeRTOS API documentation for details. #endif +#if configMAX_PRIORITIES < 1 + #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. +#endif + #ifndef configUSE_PREEMPTION #error Missing definition: configUSE_PREEMPTION must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif @@ -142,10 +146,6 @@ extern "C" { #error Missing definition: configUSE_16_BIT_TICKS must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif -#ifndef configMAX_PRIORITIES - #error configMAX_PRIORITIES must be defined to be greater than or equal to 1. -#endif - #ifndef configUSE_CO_ROUTINES #define configUSE_CO_ROUTINES 0 #endif @@ -408,6 +408,14 @@ extern "C" { #define configCHECK_FOR_STACK_OVERFLOW 0 #endif +#ifndef configRECORD_STACK_HIGH_ADDRESS + #define configRECORD_STACK_HIGH_ADDRESS 0 +#endif + +#ifndef configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H + #define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 0 +#endif + /* The following event macros are embedded in the kernel API calls. */ #ifndef traceMOVED_TASK_TO_READY_STATE @@ -708,6 +716,10 @@ extern "C" { #define configUSE_TICKLESS_IDLE 0 #endif +#ifndef configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING + #define configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( x ) +#endif + #ifndef configPRE_SLEEP_PROCESSING #define configPRE_SLEEP_PROCESSING( x ) #endif @@ -724,6 +736,10 @@ extern "C" { #define portTASK_USES_FLOATING_POINT() #endif +#ifndef portTASK_CALLS_SECURE_FUNCTIONS + #define portTASK_CALLS_SECURE_FUNCTIONS() +#endif + #ifndef configUSE_TIME_SLICING #define configUSE_TIME_SLICING 1 #endif @@ -782,6 +798,12 @@ extern "C" { #define configSUPPORT_DYNAMIC_ALLOCATION 1 #endif +#ifndef configSTACK_DEPTH_TYPE + /* Defaults to uint16_t for backward compatibility, but can be overridden + in FreeRTOSConfig.h if uint16_t is too restrictive. */ + #define configSTACK_DEPTH_TYPE uint16_t +#endif + /* Sanity check the configuration. */ #if( configUSE_TICKLESS_IDLE != 0 ) #if( INCLUDE_vTaskSuspend != 1 ) @@ -797,6 +819,10 @@ extern "C" { #error configUSE_MUTEXES must be set to 1 to use recursive mutexes #endif +#ifndef configINITIAL_TICK_COUNT + #define configINITIAL_TICK_COUNT 0 +#endif + #if( portTICK_TYPE_IS_ATOMIC == 0 ) /* Either variables of tick type cannot be read atomically, or portTICK_TYPE_IS_ATOMIC was not set - map the critical sections used when @@ -917,7 +943,7 @@ typedef struct xSTATIC_TCB UBaseType_t uxDummy5; void *pxDummy6; uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ]; - #if ( portSTACK_GROWTH > 0 ) + #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) ) void *pxDummy8; #endif #if ( portCRITICAL_NESTING_IN_TCB == 1 ) @@ -945,10 +971,14 @@ typedef struct xSTATIC_TCB uint32_t ulDummy18; uint8_t ucDummy19; #endif - #if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + #if( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) ) uint8_t uxDummy20; #endif + #if( INCLUDE_xTaskAbortDelay == 1 ) + uint8_t ucDummy21; + #endif + } StaticTask_t; /* diff --git a/FreeRTOS/Source/include/FreeRTOSConfig.h b/FreeRTOS/Source/include/FreeRTOSConfig.h index 7df92bf..2d87844 100644 --- a/FreeRTOS/Source/include/FreeRTOSConfig.h +++ b/FreeRTOS/Source/include/FreeRTOSConfig.h @@ -1,15 +1,38 @@ -/* Default esp-open-sdk FreeRTOSConfig file. +/* + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. + All rights reserved - You can override settings in here by creating your own - FreeRTOSConfig.h file in your program directory. + VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - You could just copy this file there and edit it, but it's - recommended you instead define whatever you want to override and - then use #include_next to pick up these defaults. + This file is part of the FreeRTOS distribution. - The "blink" example in "examples/blink" provides an example of how - to do this. + FreeRTOS is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License (version 2) as published by the + Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception. + + *************************************************************************** + >>! NOTE: The modification to the GPL is included to allow you to !<< + >>! distribute a combined work that includes FreeRTOS without being !<< + >>! obliged to provide the source code for proprietary components !<< + >>! outside of the FreeRTOS kernel. !<< + *************************************************************************** + + FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. Full license text is available on the following + link: http://www.freertos.org/a00114.html + + + For esp-open-rtos, you can override settings in here by creating your own + FreeRTOSConfig.h file in your program directory. You could just copy this + file there and edit it, but it's recommended you instead define whatever you + want to override and then use #include_next to pick up + these defaults. The "blink" example in "examples/blink" provides an example + of how to do this. + + 1 tab == 4 spaces! */ + #ifndef __DEFAULT_FREERTOS_CONFIG_H #define __DEFAULT_FREERTOS_CONFIG_H @@ -20,7 +43,7 @@ * application requirements. * * THESE PARAMETERS ARE DESCRIBED WITHIN THE 'CONFIGURATION' SECTION OF THE - * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. + * FreeRTOS API DOCUMENTATION AVAILABLE ON THE FreeRTOS.org WEB SITE. * * See http://www.freertos.org/a00110.html. *----------------------------------------------------------*/ @@ -47,7 +70,7 @@ #define configTICK_RATE_HZ ( ( TickType_t ) 100 ) #endif #ifndef configMAX_PRIORITIES -#define configMAX_PRIORITIES ( ( unsigned portBASE_TYPE ) 15 ) +#define configMAX_PRIORITIES ( 15 ) #endif #ifndef configMINIMAL_STACK_SIZE #define configMINIMAL_STACK_SIZE ( ( unsigned short )256 ) @@ -108,6 +131,10 @@ #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) #endif +#ifndef configUSE_NEWLIB_REENTRANT +#define configUSE_NEWLIB_REENTRANT 1 +#endif + /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #ifndef INCLUDE_vTaskPrioritySet @@ -144,5 +171,10 @@ to exclude the API function. */ #define configENABLE_BACKWARD_COMPATIBILITY 0 #endif +/* Normal assert() semantics without relying on the provision of an assert.h +header file. */ +void vAssertCalled(const char * pcFile, unsigned long ulLine); +#define configASSERT(x) if((x) == 0) vAssertCalled(__FILE__, __LINE__); + #endif /* __DEFAULT_FREERTOS_CONFIG_H */ diff --git a/FreeRTOS/Source/include/StackMacros.h b/FreeRTOS/Source/include/StackMacros.h index 13c6b82..a3f9335 100644 --- a/FreeRTOS/Source/include/StackMacros.h +++ b/FreeRTOS/Source/include/StackMacros.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/include/croutine.h b/FreeRTOS/Source/include/croutine.h index 4f003a0..f6390de 100644 --- a/FreeRTOS/Source/include/croutine.h +++ b/FreeRTOS/Source/include/croutine.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/include/deprecated_definitions.h b/FreeRTOS/Source/include/deprecated_definitions.h index 4ea816c..de7aef7 100644 --- a/FreeRTOS/Source/include/deprecated_definitions.h +++ b/FreeRTOS/Source/include/deprecated_definitions.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/include/event_groups.h b/FreeRTOS/Source/include/event_groups.h index 7331c91..81b66ca 100644 --- a/FreeRTOS/Source/include/event_groups.h +++ b/FreeRTOS/Source/include/event_groups.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/include/list.h b/FreeRTOS/Source/include/list.h index a080d27..e0f5c27 100644 --- a/FreeRTOS/Source/include/list.h +++ b/FreeRTOS/Source/include/list.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -205,7 +205,7 @@ typedef struct xMINI_LIST_ITEM MiniListItem_t; typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ - configLIST_VOLATILE UBaseType_t uxNumberOfItems; + volatile UBaseType_t uxNumberOfItems; ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */ MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ diff --git a/FreeRTOS/Source/include/mpu_prototypes.h b/FreeRTOS/Source/include/mpu_prototypes.h index 8f7500b..fcc9180 100644 --- a/FreeRTOS/Source/include/mpu_prototypes.h +++ b/FreeRTOS/Source/include/mpu_prototypes.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -83,6 +83,7 @@ BaseType_t MPU_xTaskCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask ); TaskHandle_t MPU_xTaskCreateStatic( TaskFunction_t pxTaskCode, const char * const pcName, const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, StaticTask_t * const pxTaskBuffer ); BaseType_t MPU_xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); +BaseType_t MPU_xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ); void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const pxRegions ); void MPU_vTaskDelete( TaskHandle_t xTaskToDelete ); void MPU_vTaskDelay( const TickType_t xTicksToDelay ); @@ -124,7 +125,9 @@ BaseType_t MPU_xTaskGetSchedulerState( void ); /* MPU versions of queue.h API function. */ BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition ); -BaseType_t MPU_xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ); +BaseType_t MPU_xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ); +BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ); +BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ); UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t xQueue ); UBaseType_t MPU_uxQueueSpacesAvailable( const QueueHandle_t xQueue ); void MPU_vQueueDelete( QueueHandle_t xQueue ); diff --git a/FreeRTOS/Source/include/mpu_wrappers.h b/FreeRTOS/Source/include/mpu_wrappers.h index 78f5a9a..76315e0 100644 --- a/FreeRTOS/Source/include/mpu_wrappers.h +++ b/FreeRTOS/Source/include/mpu_wrappers.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -130,7 +130,9 @@ only for ports that are using the MPU. */ /* Map standard queue.h API functions to the MPU equivalents. */ #define xQueueGenericSend MPU_xQueueGenericSend - #define xQueueGenericReceive MPU_xQueueGenericReceive + #define xQueueReceive MPU_xQueueReceive + #define xQueuePeek MPU_xQueuePeek + #define xQueueSemaphoreTake MPU_xQueueSemaphoreTake #define uxQueueMessagesWaiting MPU_uxQueueMessagesWaiting #define uxQueueSpacesAvailable MPU_uxQueueSpacesAvailable #define vQueueDelete MPU_vQueueDelete @@ -177,8 +179,11 @@ only for ports that are using the MPU. */ #define xEventGroupSync MPU_xEventGroupSync #define vEventGroupDelete MPU_vEventGroupDelete - /* Remove the privileged function macro. */ + /* Remove the privileged function macro, but keep the PRIVILEGED_DATA + macro so applications can place data in privileged access sections + (useful when using statically allocated objects). */ #define PRIVILEGED_FUNCTION + #define PRIVILEGED_DATA __attribute__((section("privileged_data"))) #else /* MPU_WRAPPERS_INCLUDED_FROM_API_FILE */ diff --git a/FreeRTOS/Source/include/portable.h b/FreeRTOS/Source/include/portable.h index b9f8be3..5e8303a 100644 --- a/FreeRTOS/Source/include/portable.h +++ b/FreeRTOS/Source/include/portable.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/include/projdefs.h b/FreeRTOS/Source/include/projdefs.h index 0b63fd8..a08f658 100644 --- a/FreeRTOS/Source/include/projdefs.h +++ b/FreeRTOS/Source/include/projdefs.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h index 30be360..bbba834 100644 --- a/FreeRTOS/Source/include/queue.h +++ b/FreeRTOS/Source/include/queue.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -696,12 +696,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ *
  BaseType_t xQueuePeek(
 							 QueueHandle_t xQueue,
-							 void *pvBuffer,
+							 void * const pvBuffer,
 							 TickType_t xTicksToWait
 						 );
* - * This is a macro that calls the xQueueGenericReceive() function. - * * Receive an item from a queue without removing the item from the queue. * The item is received by copy so a buffer of adequate size must be * provided. The number of bytes copied into the buffer was defined when @@ -782,10 +780,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQ // ... Rest of task code. } - * \defgroup xQueueReceive xQueueReceive + * \defgroup xQueuePeek xQueuePeek * \ingroup QueueManagement */ -#define xQueuePeek( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdTRUE ) +BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * queue. h @@ -829,8 +827,6 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV TickType_t xTicksToWait ); * - * This is a macro that calls the xQueueGenericReceive() function. - * * Receive an item from a queue. The item is received by copy so a buffer of * adequate size must be provided. The number of bytes copied into the buffer * was defined when the queue was created. @@ -911,106 +907,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ) PRIV * \defgroup xQueueReceive xQueueReceive * \ingroup QueueManagement */ -#define xQueueReceive( xQueue, pvBuffer, xTicksToWait ) xQueueGenericReceive( ( xQueue ), ( pvBuffer ), ( xTicksToWait ), pdFALSE ) - - -/** - * queue. h - *
- BaseType_t xQueueGenericReceive(
-									   QueueHandle_t	xQueue,
-									   void	*pvBuffer,
-									   TickType_t	xTicksToWait
-									   BaseType_t	xJustPeek
-									);
- * - * 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: -
- 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.
- }
- 
- * \defgroup xQueueReceive xQueueReceive - * \ingroup QueueManagement - */ -BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeek ) PRIVILEGED_FUNCTION; +BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; /** * queue. h @@ -1560,7 +1457,9 @@ QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) PRIVILEGED_FUNCTION QueueHandle_t xQueueCreateMutexStatic( const uint8_t ucQueueType, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) PRIVILEGED_FUNCTION; QueueHandle_t xQueueCreateCountingSemaphoreStatic( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) PRIVILEGED_FUNCTION; +BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION; void* xQueueGetMutexHolder( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; +void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore ) PRIVILEGED_FUNCTION; /* * For internal use only. Use xSemaphoreTakeMutexRecursive() or diff --git a/FreeRTOS/Source/include/semphr.h b/FreeRTOS/Source/include/semphr.h index a674b02..fb76636 100644 --- a/FreeRTOS/Source/include/semphr.h +++ b/FreeRTOS/Source/include/semphr.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -328,7 +328,7 @@ typedef QueueHandle_t SemaphoreHandle_t; * \defgroup xSemaphoreTake xSemaphoreTake * \ingroup Semaphores */ -#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE ) +#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) ) /** * semphr. h @@ -392,23 +392,23 @@ typedef QueueHandle_t SemaphoreHandle_t; // ... // For some reason due to the nature of the code further calls to - // xSemaphoreTakeRecursive() are made on the same mutex. In real - // code these would not be just sequential calls as this would make - // no sense. Instead the calls are likely to be buried inside - // a more complex call structure. + // xSemaphoreTakeRecursive() are made on the same mutex. In real + // code these would not be just sequential calls as this would make + // no sense. Instead the calls are likely to be buried inside + // a more complex call structure. xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); xSemaphoreTakeRecursive( xMutex, ( TickType_t ) 10 ); // The mutex has now been 'taken' three times, so will not be - // available to another task until it has also been given back - // three times. Again it is unlikely that real code would have - // these calls sequentially, but instead buried in a more complex - // call structure. This is just for illustrative purposes. + // available to another task until it has also been given back + // three times. Again it is unlikely that real code would have + // these calls sequentially, but instead buried in a more complex + // call structure. This is just for illustrative purposes. + xSemaphoreGiveRecursive( xMutex ); + xSemaphoreGiveRecursive( xMutex ); xSemaphoreGiveRecursive( xMutex ); - xSemaphoreGiveRecursive( xMutex ); - xSemaphoreGiveRecursive( xMutex ); - // Now the mutex can be taken by other tasks. + // Now the mutex can be taken by other tasks. } else { @@ -1154,6 +1154,17 @@ typedef QueueHandle_t SemaphoreHandle_t; */ #define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) ) +/** + * semphr.h + *
TaskHandle_t xSemaphoreGetMutexHolderFromISR( SemaphoreHandle_t xMutex );
+ * + * 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 *
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore );
diff --git a/FreeRTOS/Source/include/task.h b/FreeRTOS/Source/include/task.h index d0643c0..c326ead 100644 --- a/FreeRTOS/Source/include/task.h +++ b/FreeRTOS/Source/include/task.h @@ -1,5 +1,5 @@ /* - FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd. + FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd. All rights reserved VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. @@ -160,6 +160,9 @@ typedef struct xTASK_PARAMETERS UBaseType_t uxPriority; StackType_t *puxStackBuffer; MemoryRegion_t xRegions[ portNUM_CONFIGURABLE_REGIONS ]; + #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + StaticTask_t * const pxTaskBuffer; + #endif } TaskParameters_t; /* Used with the uxTaskGetSystemState() function to return the state of each task @@ -269,7 +272,7 @@ is used in assert() statements. */ BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, - uint16_t usStackDepth, + configSTACK_DEPTH_TYPE usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pvCreatedTask @@ -358,11 +361,11 @@ is used in assert() statements. */ */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, - const char * const pcName, - const uint16_t usStackDepth, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, void * const pvParameters, UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; #endif /** @@ -474,12 +477,12 @@ is used in assert() statements. */ */ #if( configSUPPORT_STATIC_ALLOCATION == 1 ) TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, - const char * const pcName, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ const uint32_t ulStackDepth, void * const pvParameters, UBaseType_t uxPriority, StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION; #endif /* configSUPPORT_STATIC_ALLOCATION */ /** @@ -487,6 +490,8 @@ is used in assert() statements. */ *
  BaseType_t xTaskCreateRestricted( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
* + * Only available when configSUPPORT_DYNAMIC_ALLOCATION is set to 1. + * * xTaskCreateRestricted() should only be used in systems that include an MPU * implementation. * @@ -494,6 +499,9 @@ is used in assert() statements. */ * The function parameters define the memory regions and associated access * permissions allocated to the task. * + * See xTaskCreateRestrictedStatic() for a version that does not use any + * dynamic memory allocation. + * * @param pxTaskDefinition Pointer to a structure that contains a member * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API * documentation) plus an optional stack buffer and the memory region @@ -553,6 +561,94 @@ TaskHandle_t xHandle; BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask ) PRIVILEGED_FUNCTION; #endif +/** + * task. h + *
+ BaseType_t xTaskCreateRestrictedStatic( TaskParameters_t *pxTaskDefinition, TaskHandle_t *pxCreatedTask );
+ * + * 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: +
+// 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( ;; );
+}
+   
+ * \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 *
@@ -2141,14 +2237,14 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
  * Removes a task from both the specified event list and the list of blocked
  * tasks, and places it on a ready queue.
  *
- * xTaskRemoveFromEventList()/xTaskRemoveFromUnorderedEventList() will be called
+ * xTaskRemoveFromEventList()/vTaskRemoveFromUnorderedEventList() will be called
  * if either an event occurs to unblock a task, or the block timeout period
  * expires.
  *
  * xTaskRemoveFromEventList() is used when the event list is in task priority
  * order.  It removes the list item from the head of the event list as that will
  * have the highest priority owning task of all the tasks on the event list.
- * xTaskRemoveFromUnorderedEventList() is used when the event list is not
+ * vTaskRemoveFromUnorderedEventList() is used when the event list is not
  * ordered and the event list items hold something other than the owning tasks
  * priority.  In this case the event list item value is updated to the value
  * passed in the xItemValue parameter.
@@ -2157,7 +2253,7 @@ void vTaskPlaceOnEventListRestricted( List_t * const pxEventList, TickType_t xTi
  * making the call, otherwise pdFALSE.
  */
 BaseType_t xTaskRemoveFromEventList( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
-BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
+void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
 
 /*
  * THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE.  IT IS ONLY
@@ -2207,7 +2303,7 @@ BaseType_t xTaskGetSchedulerState( void ) PRIVILEGED_FUNCTION;
  * Raises the priority of the mutex holder to that of the calling task should
  * the mutex holder have a priority less than the calling task.
  */
-void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
+BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
 
 /*
  * Set the priority of a task back to its proper priority in the case that it
@@ -2215,6 +2311,16 @@ void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTIO
  */
 BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) PRIVILEGED_FUNCTION;
 
+/*
+ * If a higher priority task attempting to obtain a mutex caused a lower
+ * priority task to inherit the higher priority task's priority - but the higher
+ * priority task then timed out without obtaining the mutex, then the lower
+ * priority task will disinherit the priority again - but only down as far as
+ * the highest priority task that is still waiting for the mutex (if there were
+ * more than one task waiting for the mutex).
+ */
+void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask ) PRIVILEGED_FUNCTION;
+
 /*
  * Get the uxTCBNumber assigned to the task referenced by the xTask parameter.
  */
@@ -2258,6 +2364,13 @@ eSleepModeStatus eTaskConfirmSleepModeStatus( void ) PRIVILEGED_FUNCTION;
  */
 void *pvTaskIncrementMutexHeldCount( void ) PRIVILEGED_FUNCTION;
 
+/*
+ * For internal use only.  Same as vTaskSetTimeOutState(), but without a critial
+ * section.
+ */
+void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ) PRIVILEGED_FUNCTION;
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/FreeRTOS/Source/include/timers.h b/FreeRTOS/Source/include/timers.h
index 798c955..449e49c 100644
--- a/FreeRTOS/Source/include/timers.h
+++ b/FreeRTOS/Source/include/timers.h
@@ -1,5 +1,5 @@
 /*
-    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
     All rights reserved
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@@ -75,10 +75,10 @@
 	#error "include FreeRTOS.h must appear in source files before include timers.h"
 #endif
 
-/*lint -e537 This headers are only multiply included if the application code
+/*lint -save -e537 This headers are only multiply included if the application code
 happens to also be including task.h. */
 #include "task.h"
-/*lint +e537 */
+/*lint -restore */
 
 #ifdef __cplusplus
 extern "C" {
@@ -266,11 +266,11 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
  * @endverbatim
  */
 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
-	TimerHandle_t xTimerCreate(	const char * const pcTimerName,
+	TimerHandle_t xTimerCreate(	const char * const pcTimerName,			/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 								const TickType_t xTimerPeriodInTicks,
 								const UBaseType_t uxAutoReload,
 								void * const pvTimerID,
-								TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+								TimerCallbackFunction_t pxCallbackFunction ) PRIVILEGED_FUNCTION;
 #endif
 
 /**
@@ -396,12 +396,12 @@ typedef void (*PendedFunction_t)( void *, uint32_t );
  * @endverbatim
  */
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
-	TimerHandle_t xTimerCreateStatic(	const char * const pcTimerName,
+	TimerHandle_t xTimerCreateStatic(	const char * const pcTimerName,			/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 										const TickType_t xTimerPeriodInTicks,
 										const UBaseType_t uxAutoReload,
 										void * const pvTimerID,
 										TimerCallbackFunction_t pxCallbackFunction,
-										StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+										StaticTimer_t *pxTimerBuffer ) PRIVILEGED_FUNCTION;
 #endif /* configSUPPORT_STATIC_ALLOCATION */
 
 /**
diff --git a/FreeRTOS/Source/list.c b/FreeRTOS/Source/list.c
index 5e207c1..f890e87 100644
--- a/FreeRTOS/Source/list.c
+++ b/FreeRTOS/Source/list.c
@@ -1,5 +1,5 @@
 /*
-    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
     All rights reserved
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c
index 87d846f..d6b2a89 100644
--- a/FreeRTOS/Source/portable/esp8266/port.c
+++ b/FreeRTOS/Source/portable/esp8266/port.c
@@ -1,5 +1,5 @@
 /*
-    FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
 
@@ -73,10 +73,12 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "FreeRTOS.h"
 #include "task.h"
+#include "queue.h"
 #include "xtensa_rtos.h"
 
 unsigned cpu_sr;
@@ -91,6 +93,13 @@ char level1_int_disabled;
 */
 void *xPortSupervisorStackPointer;
 
+void vAssertCalled(const char * pcFile, unsigned long ulLine)
+{
+    printf("rtos assert %s %lu\n", pcFile, ulLine);
+    abort();
+    //for (;;);
+}
+
 /*
  * Stack initialization
  */
@@ -100,7 +109,7 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
     portSTACK_TYPE *sp, *tp;
 
     /* Create interrupt stack frame aligned to 16 byte boundary */
-    sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack+1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf);
+    sp = (portSTACK_TYPE*) (((uint32_t)(pxTopOfStack + 1) - XT_CP_SIZE - XT_STK_FRMSZ) & ~0xf);
 
     /* Clear the entire frame (do not use memset() because we don't depend on C library) */
     for (tp = sp; tp <= pxTopOfStack; ++tp)
@@ -121,30 +130,29 @@ portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, TaskFunctio
 static int pending_soft_sv;
 static int pending_maclayer_sv;
 
-/* PendSV is called in place of vPortYield() to request a supervisor
-   call.
-
-   The portYIELD macro calls pendSV if it's a software request.
-
-   The libpp and libudhcp libraries also call this function, assuming
-   always with arg==2 (but maybe sometimes with arg==1?)
-
-   In the original esp_iot_rtos_sdk implementation, arg was a char. Using an
-   enum is ABI-compatible, though.
-*/
+/*
+ * The portYIELD macro calls PendSV with SVC_Software to set a pending interrupt
+ * service callback that allows a task switch, and this occur when interrupts
+ * are enabled which might be after exiting the critical region below.
+ *
+ * The wdev NMI calls this function from pp_post() with SVC_MACLayer to set a
+ * pending interrupt service callback which flushs the queue of messages that
+ * the NMI stashes away. This interrupt will be triggered after the return from
+ * the NMI and when interrupts are enabled. The NMI can not touch the FreeRTOS
+ * queues itself. The NMI must not touch the interrupt masks so that path must
+ * not call vPortEnterCritical and vPortExitCritical.
+ */
 void IRAM PendSV(enum SVC_ReqType req)
 {
-	vPortEnterCritical();
-
-	if(req == SVC_Software)
-	{
-		pending_soft_sv = 1;
-	}
-	else if(req == SVC_MACLayer)
-		pending_maclayer_sv= 1;
-
-	WSR(BIT(INUM_SOFT), interrupt);
-	vPortExitCritical();
+    if (req == SVC_Software) {
+        vPortEnterCritical();
+        pending_soft_sv = 1;
+        WSR(BIT(INUM_SOFT), interrupt);
+        vPortExitCritical();
+    } else if (req == SVC_MACLayer) {
+        pending_maclayer_sv= 1;
+        WSR(BIT(INUM_SOFT), interrupt);
+    }
 }
 
 /* This MAC layer ISR handler is defined in libpp.a, and is called
@@ -153,31 +161,24 @@ void IRAM PendSV(enum SVC_ReqType req)
  */
 extern portBASE_TYPE sdk_MacIsrSigPostDefHdl(void);
 
-void IRAM SV_ISR(void)
+void IRAM SV_ISR(void *arg)
 {
-	portBASE_TYPE xHigherPriorityTaskWoken=pdFALSE ;
-	if(pending_maclayer_sv)
-	{
-		xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
-		pending_maclayer_sv = 0;
-	}
-	if( xHigherPriorityTaskWoken || pending_soft_sv)
-	{
-	    sdk__xt_timer_int1();
-	    pending_soft_sv = 0;
-	}
+    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE ;
+    if (pending_maclayer_sv) {
+        xHigherPriorityTaskWoken = sdk_MacIsrSigPostDefHdl();
+        pending_maclayer_sv = 0;
+    }
+    if (xHigherPriorityTaskWoken || pending_soft_sv) {
+        sdk__xt_timer_int1();
+        pending_soft_sv = 0;
+    }
 }
 
 void xPortSysTickHandle (void)
 {
-	//CloseNMI();
-	{
-		if(xTaskIncrementTick() !=pdFALSE )
-		{
-			vTaskSwitchContext();
-		}
-	}
-	//OpenNMI();
+    if (xTaskIncrementTick() != pdFALSE) {
+        vTaskSwitchContext();
+    }
 }
 
 /*
@@ -185,11 +186,11 @@ void xPortSysTickHandle (void)
  */
 portBASE_TYPE xPortStartScheduler( void )
 {
-    _xt_isr_attach(INUM_SOFT, SV_ISR);
+    _xt_isr_attach(INUM_SOFT, SV_ISR, NULL);
     _xt_isr_unmask(BIT(INUM_SOFT));
 
     /* Initialize system tick timer interrupt and schedule the first tick. */
-    _xt_isr_attach(INUM_TICK, sdk__xt_timer_int);
+    _xt_isr_attach(INUM_TICK, sdk__xt_timer_int, NULL);
     _xt_isr_unmask(BIT(INUM_TICK));
     sdk__xt_tick_timer_init();
 
@@ -221,8 +222,10 @@ size_t xPortGetFreeHeapSize( void )
     uint32_t brk_val = (uint32_t) sbrk(0);
 
     intptr_t sp = (intptr_t)xPortSupervisorStackPointer;
-    if(sp == 0) /* scheduler not started */
+    if (sp == 0) {
+        /* scheduler not started */
         SP(sp);
+    }
     return sp - brk_val + mi.fordblks;
 }
 
@@ -233,8 +236,6 @@ void vPortEndScheduler( void )
 
 /*-----------------------------------------------------------*/
 
-/* Each task maintains its own interrupt status in the critical nesting
-variable. */
 static unsigned portBASE_TYPE uxCriticalNesting = 0;
 
 /* These nested vPortEnter/ExitCritical macros are called by SDK
@@ -243,26 +244,42 @@ static unsigned portBASE_TYPE uxCriticalNesting = 0;
  * It may be possible to replace the global nesting count variable
  * with a save/restore of interrupt level, although it's difficult as
  * the functions have no return value.
+ *
+ * These should not be called from the NMI in regular operation and
+ * the NMI must not touch the interrupt mask, but that might occur in
+ * exceptional paths such as aborts and debug code.
  */
-void IRAM vPortEnterCritical( void )
-{
+void IRAM vPortEnterCritical(void) {
     portDISABLE_INTERRUPTS();
     uxCriticalNesting++;
 }
+
 /*-----------------------------------------------------------*/
 
-void IRAM vPortExitCritical( void )
-{
+void IRAM vPortExitCritical(void) {
     uxCriticalNesting--;
-    if( uxCriticalNesting == 0 )
-	portENABLE_INTERRUPTS();
+    if (uxCriticalNesting == 0)
+        portENABLE_INTERRUPTS();
 }
 
-/* Backward compatibility with libmain.a and libpp.a and can remove when these are open. */
-signed portBASE_TYPE xTaskGenericCreate( TaskFunction_t pxTaskCode, const signed char * const pcName, unsigned short usStackDepth, void *pvParameters, unsigned portBASE_TYPE uxPriority, TaskHandle_t *pxCreatedTask, portSTACK_TYPE *puxStackBuffer, const MemoryRegion_t * const xRegions )
-{
-    (void)puxStackBuffer; (void)xRegions;
-    return xTaskCreate( pxTaskCode, (const char * const)pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
+/* Backward compatibility, for the sdk library. */
+
+signed portBASE_TYPE xTaskGenericCreate(TaskFunction_t pxTaskCode,
+                                        const signed char * const pcName,
+                                        unsigned short usStackDepth,
+                                        void *pvParameters,
+                                        unsigned portBASE_TYPE uxPriority,
+                                        TaskHandle_t *pxCreatedTask,
+                                        portSTACK_TYPE *puxStackBuffer,
+                                        const MemoryRegion_t * const xRegions) {
+    (void)puxStackBuffer;
+    (void)xRegions;
+    return xTaskCreate(pxTaskCode, (const char * const)pcName, usStackDepth,
+                       pvParameters, uxPriority, pxCreatedTask);
 }
 
-
+BaseType_t xQueueGenericReceive(QueueHandle_t xQueue, void * const pvBuffer,
+                                TickType_t xTicksToWait, const BaseType_t xJustPeeking) {
+    configASSERT(xJustPeeking == 0);
+    return xQueueReceive(xQueue, pvBuffer, xTicksToWait);
+}
diff --git a/FreeRTOS/Source/portable/esp8266/portmacro.h b/FreeRTOS/Source/portable/esp8266/portmacro.h
index 68d5e57..0b18b47 100644
--- a/FreeRTOS/Source/portable/esp8266/portmacro.h
+++ b/FreeRTOS/Source/portable/esp8266/portmacro.h
@@ -1,65 +1,29 @@
 /*
-    FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
+    All rights reserved
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
 
-    ***************************************************************************
-     *                                                                       *
-     *    FreeRTOS provides completely free yet professionally developed,    *
-     *    robust, strictly quality controlled, supported, and cross          *
-     *    platform software that has become a de facto standard.             *
-     *                                                                       *
-     *    Help yourself get started quickly and support the FreeRTOS         *
-     *    project by purchasing a FreeRTOS tutorial book, reference          *
-     *    manual, or both from: http://www.FreeRTOS.org/Documentation        *
-     *                                                                       *
-     *    Thank you!                                                         *
-     *                                                                       *
-    ***************************************************************************
-
     This file is part of the FreeRTOS distribution.
 
     FreeRTOS is free software; you can redistribute it and/or modify it under
     the terms of the GNU General Public License (version 2) as published by the
-    Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+    Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
 
-    >>! NOTE: The modification to the GPL is included to allow you to distribute
-    >>! a combined work that includes FreeRTOS without being obliged to provide
-    >>! the source code for proprietary components outside of the FreeRTOS
-    >>! kernel.
+    ***************************************************************************
+    >>!   NOTE: The modification to the GPL is included to allow you to     !<<
+    >>!   distribute a combined work that includes FreeRTOS without being   !<<
+    >>!   obliged to provide the source code for proprietary components     !<<
+    >>!   outside of the FreeRTOS kernel.                                   !<<
+    ***************************************************************************
 
     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-    FOR A PARTICULAR PURPOSE.  Full license text is available from the following
+    FOR A PARTICULAR PURPOSE.  Full license text is available on the following
     link: http://www.freertos.org/a00114.html
 
     1 tab == 4 spaces!
 
-    ***************************************************************************
-     *                                                                       *
-     *    Having a problem?  Start by reading the FAQ "My application does   *
-     *    not run, what could be wrong?"                                     *
-     *                                                                       *
-     *    http://www.FreeRTOS.org/FAQHelp.html                               *
-     *                                                                       *
-    ***************************************************************************
-
-    http://www.FreeRTOS.org - Documentation, books, training, latest versions,
-    license and Real Time Engineers Ltd. contact details.
-
-    http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
-    including FreeRTOS+Trace - an indispensable productivity tool, a DOS
-    compatible FAT file system, and our tiny thread aware UDP/IP stack.
-
-    http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
-    Integrity Systems to sell under the OpenRTOS brand.  Low cost OpenRTOS
-    licenses offer ticketed support, indemnification and middleware.
-
-    http://www.SafeRTOS.com - High Integrity Systems also provide a safety
-    engineered and independently SIL3 certified version for use in safety and
-    mission critical applications that require provable dependability.
-
-    1 tab == 4 spaces!
 */
 
 
@@ -92,16 +56,15 @@ extern "C" {
 #define portDOUBLE              double
 #define portLONG                long
 #define portSHORT               short
-#define portSTACK_TYPE          unsigned portLONG
+#define portSTACK_TYPE          uint32_t
 #define portBASE_TYPE           long
-#define portPOINTER_SIZE_TYPE   unsigned portLONG
 
 typedef portSTACK_TYPE StackType_t;
 typedef portBASE_TYPE BaseType_t;
 typedef unsigned portBASE_TYPE UBaseType_t;
 
 typedef uint32_t TickType_t;
-#define portMAX_DELAY ( TickType_t ) 0xffffffff
+#define portMAX_DELAY ( TickType_t ) 0xffffffffUL
 
 /* Architecture specifics. */
 #define portSTACK_GROWTH			( -1 )
@@ -156,6 +119,9 @@ extern unsigned cpu_sr;
    prefer to _xt_disable_interrupts & _xt_enable_interrupts and store
    the ps value in a local variable - that approach is recursive-safe
    and generally better.
+
+   The NMI must not touch the interrupt mask and it should not in
+   regular operation, but there is a guard here just in case.
 */
 inline static __attribute__((always_inline)) void portDISABLE_INTERRUPTS(void)
 {
@@ -185,6 +151,10 @@ not necessary for to use this port.  They are defined so the common demo files
 (which build with all the ports) will build. */
 #define portTASK_FUNCTION_PROTO( vFunction, pvParameters ) void vFunction( void *pvParameters )
 #define portTASK_FUNCTION( vFunction, pvParameters ) void vFunction( void *pvParameters )
+
+/* FreeRTOS API functions should not be called from the NMI handler. */
+#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() configASSERT(sdk_NMIIrqIsOn == 0)
+
 /*-----------------------------------------------------------*/
 
 #ifdef __cplusplus
diff --git a/FreeRTOS/Source/portable/readme.txt b/FreeRTOS/Source/portable/readme.txt
new file mode 100644
index 0000000..b68d2d5
--- /dev/null
+++ b/FreeRTOS/Source/portable/readme.txt
@@ -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.
+
diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c
index ce623be..d076022 100644
--- a/FreeRTOS/Source/queue.c
+++ b/FreeRTOS/Source/queue.c
@@ -1,5 +1,5 @@
 /*
-    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
     All rights reserved
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@@ -255,6 +255,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
 	static void prvInitialiseMutex( Queue_t *pxNewQueue ) PRIVILEGED_FUNCTION;
 #endif
 
+#if( configUSE_MUTEXES == 1 )
+	/*
+	 * If a task waiting for a mutex causes the mutex holder to inherit a
+	 * priority, but the waiting task times out, then the holder should
+	 * disinherit the priority - but only down to the highest priority of any
+	 * other tasks that are waiting for the same mutex.  This function returns
+	 * that priority.
+	 */
+	static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
+#endif
 /*-----------------------------------------------------------*/
 
 /*
@@ -374,6 +384,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 			prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
 		}
+		else
+		{
+			traceQUEUE_CREATE_FAILED( ucQueueType );
+		}
 
 		return pxNewQueue;
 	}
@@ -422,6 +436,10 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
 			prvInitialiseNewQueue( uxQueueLength, uxItemSize, pucQueueStorage, ucQueueType, pxNewQueue );
 		}
+		else
+		{
+			traceQUEUE_CREATE_FAILED( ucQueueType );
+		}
 
 		return pxNewQueue;
 	}
@@ -567,6 +585,32 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
 #endif
 /*-----------------------------------------------------------*/
 
+#if ( ( configUSE_MUTEXES == 1 ) && ( INCLUDE_xSemaphoreGetMutexHolder == 1 ) )
+
+	void* xQueueGetMutexHolderFromISR( QueueHandle_t xSemaphore )
+	{
+	void *pxReturn;
+
+		configASSERT( xSemaphore );
+
+		/* Mutexes cannot be used in interrupt service routines, so the mutex
+		holder should not change in an ISR, and therefore a critical section is
+		not required here. */
+		if( ( ( Queue_t * ) xSemaphore )->uxQueueType == queueQUEUE_IS_MUTEX )
+		{
+			pxReturn = ( void * ) ( ( Queue_t * ) xSemaphore )->pxMutexHolder;
+		}
+		else
+		{
+			pxReturn = NULL;
+		}
+
+		return pxReturn;
+	} /*lint !e818 xSemaphore cannot be a pointer to const because it is a typedef. */
+
+#endif
+/*-----------------------------------------------------------*/
+
 #if ( configUSE_RECURSIVE_MUTEXES == 1 )
 
 	BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex )
@@ -643,7 +687,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength, const UBaseT
 		}
 		else
 		{
-			xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE );
+			xReturn = xQueueSemaphoreTake( pxMutex, xTicksToWait );
 
 			/* pdPASS will only be returned if the mutex was successfully
 			obtained.  The calling task may have entered the Blocked state
@@ -855,7 +899,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				{
 					/* The queue was full and a block time was specified so
 					configure the timeout structure. */
-					vTaskSetTimeOutState( &xTimeOut );
+					vTaskInternalSetTimeOutState( &xTimeOut );
 					xEntryTimeSet = pdTRUE;
 				}
 				else
@@ -1127,7 +1171,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			can be assumed there is no mutex holder and no need to determine if
 			priority disinheritance is needed.  Simply increase the count of
 			messages (semaphores) available. */
-			pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;
+			pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
 
 			/* The event list is not altered if the queue is locked.  This will
 			be done when the queue is unlocked later. */
@@ -1234,21 +1278,27 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 }
 /*-----------------------------------------------------------*/
 
-BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
+BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
 {
 BaseType_t xEntryTimeSet = pdFALSE;
 TimeOut_t xTimeOut;
-int8_t *pcOriginalReadPosition;
 Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 
-	configASSERT( pxQueue );
-	configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) );
+	/* Check the pointer is not NULL. */
+	configASSERT( ( pxQueue ) );
+
+	/* The buffer into which data is received can only be NULL if the data size
+	is zero (so no data is copied into the buffer. */
+	configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
+
+	/* Cannot block if the scheduler is suspended. */
 	#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
 	{
 		configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
 	}
 	#endif
 
+
 	/* This function relaxes the coding standard somewhat to allow return
 	statements within the function itself.  This is done in the interest
 	of execution time efficiency. */
@@ -1263,44 +1313,19 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			must be the highest priority task wanting to access the queue. */
 			if( uxMessagesWaiting > ( UBaseType_t ) 0 )
 			{
-				/* Remember the read position in case the queue is only being
-				peeked. */
-				pcOriginalReadPosition = pxQueue->u.pcReadFrom;
-
+				/* Data available, remove one item. */
 				prvCopyDataFromQueue( pxQueue, pvBuffer );
+				traceQUEUE_RECEIVE( pxQueue );
+				pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
 
-				if( xJustPeeking == pdFALSE )
+				/* There is now space in the queue, were any tasks waiting to
+				post to the queue?  If so, unblock the highest priority waiting
+				task. */
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
 				{
-					traceQUEUE_RECEIVE( pxQueue );
-
-					/* Actually removing data, not just peeking. */
-					pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
-
-					#if ( configUSE_MUTEXES == 1 )
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
 					{
-						if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
-						{
-							/* Record the information required to implement
-							priority inheritance should it become necessary. */
-							pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
-					}
-					#endif /* configUSE_MUTEXES */
-
-					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
-					{
-						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
-						{
-							queueYIELD_IF_USING_PREEMPTION();
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
+						queueYIELD_IF_USING_PREEMPTION();
 					}
 					else
 					{
@@ -1309,30 +1334,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				}
 				else
 				{
-					traceQUEUE_PEEK( pxQueue );
-
-					/* The data is not being removed, so reset the read
-					pointer. */
-					pxQueue->u.pcReadFrom = pcOriginalReadPosition;
-
-					/* The data is being left in the queue, so see if there are
-					any other tasks waiting for the data. */
-					if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
-					{
-						if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
-						{
-							/* The task waiting has a higher priority than this task. */
-							queueYIELD_IF_USING_PREEMPTION();
-						}
-						else
-						{
-							mtCOVERAGE_TEST_MARKER();
-						}
-					}
-					else
-					{
-						mtCOVERAGE_TEST_MARKER();
-					}
+					mtCOVERAGE_TEST_MARKER();
 				}
 
 				taskEXIT_CRITICAL();
@@ -1352,7 +1354,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 				{
 					/* The queue was empty and a block time was specified so
 					configure the timeout structure. */
-					vTaskSetTimeOutState( &xTimeOut );
+					vTaskInternalSetTimeOutState( &xTimeOut );
 					xEntryTimeSet = pdTRUE;
 				}
 				else
@@ -1373,6 +1375,182 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 		/* Update the timeout state to see if it has expired yet. */
 		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
 		{
+			/* The timeout has not expired.  If the queue is still empty place
+			the task on the list of tasks waiting to receive from the queue. */
+			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
+			{
+				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
+				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+				prvUnlockQueue( pxQueue );
+				if( xTaskResumeAll() == pdFALSE )
+				{
+					portYIELD_WITHIN_API();
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
+			}
+			else
+			{
+				/* The queue contains data again.  Loop back to try and read the
+				data. */
+				prvUnlockQueue( pxQueue );
+				( void ) xTaskResumeAll();
+			}
+		}
+		else
+		{
+			/* Timed out.  If there is no data in the queue exit, otherwise loop
+			back and attempt to read the data. */
+			prvUnlockQueue( pxQueue );
+			( void ) xTaskResumeAll();
+
+			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
+			{
+				traceQUEUE_RECEIVE_FAILED( pxQueue );
+				return errQUEUE_EMPTY;
+			}
+			else
+			{
+				mtCOVERAGE_TEST_MARKER();
+			}
+		}
+	}
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
+{
+BaseType_t xEntryTimeSet = pdFALSE;
+TimeOut_t xTimeOut;
+Queue_t * const pxQueue = ( Queue_t * ) xQueue;
+
+#if( configUSE_MUTEXES == 1 )
+	BaseType_t xInheritanceOccurred = pdFALSE;
+#endif
+
+	/* Check the queue pointer is not NULL. */
+	configASSERT( ( pxQueue ) );
+
+	/* Check this really is a semaphore, in which case the item size will be
+	0. */
+	configASSERT( pxQueue->uxItemSize == 0 );
+
+	/* Cannot block if the scheduler is suspended. */
+	#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
+	{
+		configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
+	}
+	#endif
+
+
+	/* This function relaxes the coding standard somewhat to allow return
+	statements within the function itself.  This is done in the interest
+	of execution time efficiency. */
+
+	for( ;; )
+	{
+		taskENTER_CRITICAL();
+		{
+			/* Semaphores are queues with an item size of 0, and where the
+			number of messages in the queue is the semaphore's count value. */
+			const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;
+
+			/* Is there data in the queue now?  To be running the calling task
+			must be the highest priority task wanting to access the queue. */
+			if( uxSemaphoreCount > ( UBaseType_t ) 0 )
+			{
+				traceQUEUE_RECEIVE( pxQueue );
+
+				/* Semaphores are queues with a data size of zero and where the
+				messages waiting is the semaphore's count.  Reduce the count. */
+				pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1;
+
+				#if ( configUSE_MUTEXES == 1 )
+				{
+					if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
+					{
+						/* Record the information required to implement
+						priority inheritance should it become necessary. */
+						pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				#endif /* configUSE_MUTEXES */
+
+				/* Check to see if other tasks are blocked waiting to give the
+				semaphore, and if so, unblock the highest priority such task. */
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
+				{
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
+					{
+						queueYIELD_IF_USING_PREEMPTION();
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
+
+				taskEXIT_CRITICAL();
+				return pdPASS;
+			}
+			else
+			{
+				if( xTicksToWait == ( TickType_t ) 0 )
+				{
+					/* For inheritance to have occurred there must have been an
+					initial timeout, and an adjusted timeout cannot become 0, as
+					if it were 0 the function would have exited. */
+					#if( configUSE_MUTEXES == 1 )
+					{
+						configASSERT( xInheritanceOccurred == pdFALSE );
+					}
+					#endif /* configUSE_MUTEXES */
+
+					/* The semaphore count was 0 and no block time is specified
+					(or the block time has expired) so exit now. */
+					taskEXIT_CRITICAL();
+					traceQUEUE_RECEIVE_FAILED( pxQueue );
+					return errQUEUE_EMPTY;
+				}
+				else if( xEntryTimeSet == pdFALSE )
+				{
+					/* The semaphore count was 0 and a block time was specified
+					so configure the timeout structure ready to block. */
+					vTaskInternalSetTimeOutState( &xTimeOut );
+					xEntryTimeSet = pdTRUE;
+				}
+				else
+				{
+					/* Entry time was already set. */
+					mtCOVERAGE_TEST_MARKER();
+				}
+			}
+		}
+		taskEXIT_CRITICAL();
+
+		/* Interrupts and other tasks can give to and take from the semaphore
+		now the critical section has been exited. */
+
+		vTaskSuspendAll();
+		prvLockQueue( pxQueue );
+
+		/* Update the timeout state to see if it has expired yet. */
+		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+		{
+			/* A block time is specified and not expired.  If the semaphore
+			count is 0 then enter the Blocked state to wait for a semaphore to
+			become available.  As semaphores are implemented with queues the
+			queue being empty is equivalent to the semaphore count being 0. */
 			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
 			{
 				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
@@ -1383,7 +1561,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 					{
 						taskENTER_CRITICAL();
 						{
-							vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
+							xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder );
 						}
 						taskEXIT_CRITICAL();
 					}
@@ -1407,13 +1585,193 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			}
 			else
 			{
-				/* Try again. */
+				/* There was no timeout and the semaphore count was not 0, so
+				attempt to take the semaphore again. */
 				prvUnlockQueue( pxQueue );
 				( void ) xTaskResumeAll();
 			}
 		}
 		else
 		{
+			/* Timed out. */
+			prvUnlockQueue( pxQueue );
+			( void ) xTaskResumeAll();
+
+			/* If the semaphore count is 0 exit now as the timeout has
+			expired.  Otherwise return to attempt to take the semaphore that is
+			known to be available.  As semaphores are implemented by queues the
+			queue being empty is equivalent to the semaphore count being 0. */
+			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
+			{
+				#if ( configUSE_MUTEXES == 1 )
+				{
+					/* xInheritanceOccurred could only have be set if
+					pxQueue->uxQueueType == queueQUEUE_IS_MUTEX so no need to
+					test the mutex type again to check it is actually a mutex. */
+					if( xInheritanceOccurred != pdFALSE )
+					{
+						taskENTER_CRITICAL();
+						{
+							UBaseType_t uxHighestWaitingPriority;
+
+							/* This task blocking on the mutex caused another
+							task to inherit this task's priority.  Now this task
+							has timed out the priority should be disinherited
+							again, but only as low as the next highest priority
+							task that is waiting for the same mutex. */
+							uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout( pxQueue );
+							vTaskPriorityDisinheritAfterTimeout( ( void * ) pxQueue->pxMutexHolder, uxHighestWaitingPriority );
+						}
+						taskEXIT_CRITICAL();
+					}
+				}
+				#endif /* configUSE_MUTEXES */
+
+				traceQUEUE_RECEIVE_FAILED( pxQueue );
+				return errQUEUE_EMPTY;
+			}
+			else
+			{
+				mtCOVERAGE_TEST_MARKER();
+			}
+		}
+	}
+}
+/*-----------------------------------------------------------*/
+
+BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
+{
+BaseType_t xEntryTimeSet = pdFALSE;
+TimeOut_t xTimeOut;
+int8_t *pcOriginalReadPosition;
+Queue_t * const pxQueue = ( Queue_t * ) xQueue;
+
+	/* Check the pointer is not NULL. */
+	configASSERT( ( pxQueue ) );
+
+	/* The buffer into which data is received can only be NULL if the data size
+	is zero (so no data is copied into the buffer. */
+	configASSERT( !( ( ( pvBuffer ) == NULL ) && ( ( pxQueue )->uxItemSize != ( UBaseType_t ) 0U ) ) );
+
+	/* Cannot block if the scheduler is suspended. */
+	#if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
+	{
+		configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) );
+	}
+	#endif
+
+
+	/* This function relaxes the coding standard somewhat to allow return
+	statements within the function itself.  This is done in the interest
+	of execution time efficiency. */
+
+	for( ;; )
+	{
+		taskENTER_CRITICAL();
+		{
+			const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
+
+			/* Is there data in the queue now?  To be running the calling task
+			must be the highest priority task wanting to access the queue. */
+			if( uxMessagesWaiting > ( UBaseType_t ) 0 )
+			{
+				/* Remember the read position so it can be reset after the data
+				is read from the queue as this function is only peeking the
+				data, not removing it. */
+				pcOriginalReadPosition = pxQueue->u.pcReadFrom;
+
+				prvCopyDataFromQueue( pxQueue, pvBuffer );
+				traceQUEUE_PEEK( pxQueue );
+
+				/* The data is not being removed, so reset the read pointer. */
+				pxQueue->u.pcReadFrom = pcOriginalReadPosition;
+
+				/* The data is being left in the queue, so see if there are
+				any other tasks waiting for the data. */
+				if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
+				{
+					if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
+					{
+						/* The task waiting has a higher priority than this task. */
+						queueYIELD_IF_USING_PREEMPTION();
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
+
+				taskEXIT_CRITICAL();
+				return pdPASS;
+			}
+			else
+			{
+				if( xTicksToWait == ( TickType_t ) 0 )
+				{
+					/* The queue was empty and no block time is specified (or
+					the block time has expired) so leave now. */
+					taskEXIT_CRITICAL();
+					traceQUEUE_RECEIVE_FAILED( pxQueue );
+					return errQUEUE_EMPTY;
+				}
+				else if( xEntryTimeSet == pdFALSE )
+				{
+					/* The queue was empty and a block time was specified so
+					configure the timeout structure ready to enter the blocked
+					state. */
+					vTaskInternalSetTimeOutState( &xTimeOut );
+					xEntryTimeSet = pdTRUE;
+				}
+				else
+				{
+					/* Entry time was already set. */
+					mtCOVERAGE_TEST_MARKER();
+				}
+			}
+		}
+		taskEXIT_CRITICAL();
+
+		/* Interrupts and other tasks can send to and receive from the queue
+		now the critical section has been exited. */
+
+		vTaskSuspendAll();
+		prvLockQueue( pxQueue );
+
+		/* Update the timeout state to see if it has expired yet. */
+		if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
+		{
+			/* Timeout has not expired yet, check to see if there is data in the
+			queue now, and if not enter the Blocked state to wait for data. */
+			if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
+			{
+				traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
+				vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
+				prvUnlockQueue( pxQueue );
+				if( xTaskResumeAll() == pdFALSE )
+				{
+					portYIELD_WITHIN_API();
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
+			}
+			else
+			{
+				/* There is data in the queue now, so don't enter the blocked
+				state, instead return to try and obtain the data. */
+				prvUnlockQueue( pxQueue );
+				( void ) xTaskResumeAll();
+			}
+		}
+		else
+		{
+			/* The timeout has expired.  If there is still no data in the queue
+			exit, otherwise go back and try to read the data again. */
 			prvUnlockQueue( pxQueue );
 			( void ) xTaskResumeAll();
 
@@ -1468,7 +1826,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 			traceQUEUE_RECEIVE_FROM_ISR( pxQueue );
 
 			prvCopyDataFromQueue( pxQueue, pvBuffer );
-			pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1;
+			pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
 
 			/* If the queue is locked the event list will not be modified.
 			Instead update the lock count so the task that unlocks the queue
@@ -1694,6 +2052,33 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
 #endif /* configUSE_TRACE_FACILITY */
 /*-----------------------------------------------------------*/
 
+#if( configUSE_MUTEXES == 1 )
+
+	static UBaseType_t prvGetDisinheritPriorityAfterTimeout( const Queue_t * const pxQueue )
+	{
+	UBaseType_t uxHighestPriorityOfWaitingTasks;
+
+		/* If a task waiting for a mutex causes the mutex holder to inherit a
+		priority, but the waiting task times out, then the holder should
+		disinherit the priority - but only down to the highest priority of any
+		other tasks that are waiting for the same mutex.  For this purpose,
+		return the priority of the highest priority task that is waiting for the
+		mutex. */
+		if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0 )
+		{
+			uxHighestPriorityOfWaitingTasks = configMAX_PRIORITIES - listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) );
+		}
+		else
+		{
+			uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY;
+		}
+
+		return uxHighestPriorityOfWaitingTasks;
+	}
+
+#endif /* configUSE_MUTEXES */
+/*-----------------------------------------------------------*/
+
 static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
 {
 BaseType_t xReturn = pdFALSE;
@@ -1767,7 +2152,7 @@ UBaseType_t uxMessagesWaiting;
 		}
 	}
 
-	pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1;
+	pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
 
 	return xReturn;
 }
@@ -2316,7 +2701,7 @@ BaseType_t xReturn;
 		}
 
 		return pcReturn;
-	}
+	} /*lint !e818 xQueue cannot be a pointer to const because it is a typedef. */
 
 #endif /* configQUEUE_REGISTRY_SIZE */
 /*-----------------------------------------------------------*/
@@ -2395,7 +2780,7 @@ BaseType_t xReturn;
 	{
 	QueueSetHandle_t pxQueue;
 
-		pxQueue = xQueueGenericCreate( uxEventQueueLength, sizeof( Queue_t * ), queueQUEUE_TYPE_SET );
+		pxQueue = xQueueGenericCreate( uxEventQueueLength, ( UBaseType_t ) sizeof( Queue_t * ), queueQUEUE_TYPE_SET );
 
 		return pxQueue;
 	}
@@ -2478,7 +2863,7 @@ BaseType_t xReturn;
 	{
 	QueueSetMemberHandle_t xReturn = NULL;
 
-		( void ) xQueueGenericReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait, pdFALSE ); /*lint !e961 Casting from one typedef to another is not redundant. */
+		( void ) xQueueReceive( ( QueueHandle_t ) xQueueSet, &xReturn, xTicksToWait ); /*lint !e961 Casting from one typedef to another is not redundant. */
 		return xReturn;
 	}
 
diff --git a/FreeRTOS/Source/readme.txt b/FreeRTOS/Source/readme.txt
index 58480c5..b68d2d5 100644
--- a/FreeRTOS/Source/readme.txt
+++ b/FreeRTOS/Source/readme.txt
@@ -1,17 +1,20 @@
 Each real time kernel port consists of three files that contain the core kernel
-components and are common to every port, and one or more files that are 
-specific to a particular microcontroller and or compiler.
+components and are common to every port, and one or more files that are
+specific to a particular microcontroller and/or compiler.
 
-+ The FreeRTOS/Source directory contains the three files that are common to 
-every port - list.c, queue.c and tasks.c.  The kernel is contained within these 
-three files.  croutine.c implements the optional co-routine functionality - which
-is normally only used on very memory limited systems.
 
-+ The FreeRTOS/Source/Portable directory contains the files that are specific to 
-a particular microcontroller and or compiler.
++ The FreeRTOS/Source/Portable/MemMang directory contains the five sample
+memory allocators as described on the http://www.FreeRTOS.org WEB site.
 
-+ The FreeRTOS/Source/include directory contains the real time kernel header 
-files.
++ The other directories each contain files specific to a particular
+microcontroller or compiler, where the directory name denotes the compiler
+specific files the directory contains.
+
+
+
+For example, if you are interested in the [compiler] port for the [architecture]
+microcontroller, then the port specific files are contained in
+FreeRTOS/Source/Portable/[compiler]/[architecture] directory.  If this is the
+only port you are interested in then all the other directories can be
+ignored.
 
-See the readme file in the FreeRTOS/Source/Portable directory for more 
-information.
\ No newline at end of file
diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c
index 6c261a6..dd6a69d 100644
--- a/FreeRTOS/Source/tasks.c
+++ b/FreeRTOS/Source/tasks.c
@@ -1,5 +1,5 @@
 /*
-    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
     All rights reserved
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@@ -131,12 +131,23 @@ made to free the RAM that was allocated statically.
 tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a
 task to be created using either statically or dynamically allocated RAM.  Note
 that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
-a statically allocated stack and a dynamically allocated TCB. */
-#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
+a statically allocated stack and a dynamically allocated TCB.
+!!!NOTE!!! If the definition of tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is
+changed then the definition of StaticTask_t must also be updated. */
+#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE	( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
 #define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB 		( ( uint8_t ) 0 )
 #define tskSTATICALLY_ALLOCATED_STACK_ONLY 			( ( uint8_t ) 1 )
 #define tskSTATICALLY_ALLOCATED_STACK_AND_TCB		( ( uint8_t ) 2 )
 
+/* If any of the following are set then task stacks are filled with a known
+value so the high water mark can be determined.  If none of the following are
+set then don't fill the stack so there is no unnecessary dependency on memset. */
+#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
+	#define tskSET_NEW_STACKS_TO_KNOWN_VALUE	1
+#else
+	#define tskSET_NEW_STACKS_TO_KNOWN_VALUE	0
+#endif
+
 /*
  * Macros used by vListTask to indicate which state a task is in.
  */
@@ -153,6 +164,12 @@ a statically allocated stack and a dynamically allocated TCB. */
 	#define static
 #endif
 
+/* The name allocated to the Idle task.  This can be overridden by defining
+configIDLE_TASK_NAME in FreeRTOSConfig.h. */
+#ifndef configIDLE_TASK_NAME
+	#define configIDLE_TASK_NAME "IDLE"
+#endif
+
 #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
 
 	/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
@@ -304,8 +321,8 @@ typedef struct tskTaskControlBlock
 	StackType_t			*pxStack;			/*< Points to the start of the stack. */
 	char				pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 
-	#if ( portSTACK_GROWTH > 0 )
-		StackType_t		*pxEndOfStack;		/*< Points to the end of the stack on architectures where the stack grows up from low memory. */
+	#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
+		StackType_t		*pxEndOfStack;		/*< Points to the highest valid address for the stack. */
 	#endif
 
 	#if ( portCRITICAL_NESTING_IN_TCB == 1 )
@@ -327,7 +344,7 @@ typedef struct tskTaskControlBlock
 	#endif
 
 	#if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
-		void *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
+		void			*pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
 	#endif
 
 	#if( configGENERATE_RUN_TIME_STATS == 1 )
@@ -352,7 +369,7 @@ typedef struct tskTaskControlBlock
 
 	/* See the comments above the definition of
 	tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
-	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
+	#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
 		uint8_t	ucStaticallyAllocated; 		/*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
 	#endif
 
@@ -366,8 +383,8 @@ typedef struct tskTaskControlBlock
 below to enable the use of older kernel aware debuggers. */
 typedef tskTCB TCB_t;
 
-/*lint -e956 A manual analysis and inspection has been used to determine which
-static variables must be declared volatile. */
+/*lint -save -e956 A manual analysis and inspection has been used to determine
+which static variables must be declared volatile. */
 
 PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL;
 
@@ -394,7 +411,7 @@ PRIVILEGED_DATA static List_t xPendingReadyList;						/*< Tasks that have been r
 
 /* Other file private variables. --------------------------------*/
 PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks 	= ( UBaseType_t ) 0U;
-PRIVILEGED_DATA static volatile TickType_t xTickCount 				= ( TickType_t ) 0U;
+PRIVILEGED_DATA static volatile TickType_t xTickCount 				= ( TickType_t ) configINITIAL_TICK_COUNT;
 PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority 		= tskIDLE_PRIORITY;
 PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning 		= pdFALSE;
 PRIVILEGED_DATA static volatile UBaseType_t uxPendedTicks 			= ( UBaseType_t ) 0U;
@@ -421,21 +438,27 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended	= ( UBaseType_t
 
 #endif
 
-/*lint +e956 */
+/*lint -restore */
 
 /*-----------------------------------------------------------*/
 
 /* Callback function prototypes. --------------------------*/
 #if(  configCHECK_FOR_STACK_OVERFLOW > 0 )
+
 	extern void vApplicationStackOverflowHook( TaskHandle_t xTask, char *pcTaskName );
+
 #endif
 
 #if( configUSE_TICK_HOOK > 0 )
+
 	extern void vApplicationTickHook( void );
+
 #endif
 
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
+
 	extern void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );
+
 #endif
 
 /* File private functions. --------------------------------*/
@@ -446,7 +469,9 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended	= ( UBaseType_t
  * is in any other state.
  */
 #if ( INCLUDE_vTaskSuspend == 1 )
+
 	static BaseType_t prvTaskIsTaskSuspended( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
+
 #endif /* INCLUDE_vTaskSuspend */
 
 /*
@@ -565,13 +590,13 @@ static void prvResetNextTaskUnblockTime( void );
  * dynamically to fill in the structure's members.
  */
 static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
-									const char * const pcName,
+									const char * const pcName, 		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 									const uint32_t ulStackDepth,
 									void * const pvParameters,
 									UBaseType_t uxPriority,
 									TaskHandle_t * const pxCreatedTask,
 									TCB_t *pxNewTCB,
-									const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+									const MemoryRegion_t * const xRegions ) PRIVILEGED_FUNCTION;
 
 /*
  * Called after a new task has been created and initialised to place the task
@@ -579,17 +604,28 @@ static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
  */
 static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 
+/*
+ * freertos_tasks_c_additions_init() should only be called if the user definable
+ * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
+ * called by the function.
+ */
+#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
+
+	static void freertos_tasks_c_additions_init( void ) PRIVILEGED_FUNCTION;
+
+#endif
+
 /*-----------------------------------------------------------*/
 
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
 
 	TaskHandle_t xTaskCreateStatic(	TaskFunction_t pxTaskCode,
-									const char * const pcName,
+									const char * const pcName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 									const uint32_t ulStackDepth,
 									void * const pvParameters,
 									UBaseType_t uxPriority,
 									StackType_t * const puxStackBuffer,
-									StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+									StaticTask_t * const pxTaskBuffer )
 	{
 	TCB_t *pxNewTCB;
 	TaskHandle_t xReturn;
@@ -597,6 +633,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 		configASSERT( puxStackBuffer != NULL );
 		configASSERT( pxTaskBuffer != NULL );
 
+		#if( configASSERT_DEFINED == 1 )
+		{
+			/* Sanity check that the size of the structure used to declare a
+			variable of type StaticTask_t equals the size of the real task
+			structure. */
+			volatile size_t xSize = sizeof( StaticTask_t );
+			configASSERT( xSize == sizeof( TCB_t ) );
+		}
+		#endif /* configASSERT_DEFINED */
+
+
 		if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
 		{
 			/* The memory used for the task's TCB and stack are passed into this
@@ -604,7 +651,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 			pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
 			pxNewTCB->pxStack = ( StackType_t * ) puxStackBuffer;
 
-			#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
+			#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
 			{
 				/* Tasks can be created statically or dynamically, so note this
 				task was created statically in case the task is later deleted. */
@@ -626,7 +673,53 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 #endif /* SUPPORT_STATIC_ALLOCATION */
 /*-----------------------------------------------------------*/
 
-#if( portUSING_MPU_WRAPPERS == 1 )
+#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
+
+	BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
+	{
+	TCB_t *pxNewTCB;
+	BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
+
+		configASSERT( pxTaskDefinition->puxStackBuffer != NULL );
+		configASSERT( pxTaskDefinition->pxTaskBuffer != NULL );
+
+		if( ( pxTaskDefinition->puxStackBuffer != NULL ) && ( pxTaskDefinition->pxTaskBuffer != NULL ) )
+		{
+			/* Allocate space for the TCB.  Where the memory comes from depends
+			on the implementation of the port malloc function and whether or
+			not static allocation is being used. */
+			pxNewTCB = ( TCB_t * ) pxTaskDefinition->pxTaskBuffer;
+
+			/* Store the stack location in the TCB. */
+			pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
+
+			#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
+			{
+				/* Tasks can be created statically or dynamically, so note this
+				task was created statically in case the task is later deleted. */
+				pxNewTCB->ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB;
+			}
+			#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
+
+			prvInitialiseNewTask(	pxTaskDefinition->pvTaskCode,
+									pxTaskDefinition->pcName,
+									( uint32_t ) pxTaskDefinition->usStackDepth,
+									pxTaskDefinition->pvParameters,
+									pxTaskDefinition->uxPriority,
+									pxCreatedTask, pxNewTCB,
+									pxTaskDefinition->xRegions );
+
+			prvAddNewTaskToReadyList( pxNewTCB );
+			xReturn = pdPASS;
+		}
+
+		return xReturn;
+	}
+
+#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
+/*-----------------------------------------------------------*/
+
+#if( ( portUSING_MPU_WRAPPERS == 1 ) && ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) )
 
 	BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
 	{
@@ -674,11 +767,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 
 	BaseType_t xTaskCreate(	TaskFunction_t pxTaskCode,
-							const char * const pcName,
-							const uint16_t usStackDepth,
+							const char * const pcName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+							const configSTACK_DEPTH_TYPE usStackDepth,
 							void * const pvParameters,
 							UBaseType_t uxPriority,
-							TaskHandle_t * const pxCreatedTask ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+							TaskHandle_t * const pxCreatedTask )
 	{
 	TCB_t *pxNewTCB;
 	BaseType_t xReturn;
@@ -741,7 +834,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 
 		if( pxNewTCB != NULL )
 		{
-			#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
+			#if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
 			{
 				/* Tasks can be created statically or dynamically, so note this
 				task was created dynamically in case it is later deleted. */
@@ -765,13 +858,13 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB ) PRIVILEGED_FUNCTION;
 /*-----------------------------------------------------------*/
 
 static void prvInitialiseNewTask( 	TaskFunction_t pxTaskCode,
-									const char * const pcName,
+									const char * const pcName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 									const uint32_t ulStackDepth,
 									void * const pvParameters,
 									UBaseType_t uxPriority,
 									TaskHandle_t * const pxCreatedTask,
 									TCB_t *pxNewTCB,
-									const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+									const MemoryRegion_t * const xRegions )
 {
 StackType_t *pxTopOfStack;
 UBaseType_t x;
@@ -791,12 +884,12 @@ UBaseType_t x;
 	#endif /* portUSING_MPU_WRAPPERS == 1 */
 
 	/* Avoid dependency on memset() if it is not required. */
-	#if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
+	#if( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
 	{
 		/* Fill the stack with a known value to assist debugging. */
 		( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
 	}
-	#endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
+	#endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
 
 	/* Calculate the top of stack address.  This depends on whether the stack
 	grows from high memory to low (as per the 80x86) or vice versa.
@@ -809,6 +902,14 @@ UBaseType_t x;
 
 		/* Check the alignment of the calculated top of stack is correct. */
 		configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
+
+		#if( configRECORD_STACK_HIGH_ADDRESS == 1 )
+		{
+			/* Also record the stack's high address, which may assist
+			debugging. */
+			pxNewTCB->pxEndOfStack = pxTopOfStack;
+		}
+		#endif /* configRECORD_STACK_HIGH_ADDRESS */
 	}
 	#else /* portSTACK_GROWTH */
 	{
@@ -936,7 +1037,7 @@ UBaseType_t x;
 	/* Initialize the TCB stack to look as if the task was already running,
 	but had been interrupted by the scheduler.  The return address is set
 	to the start of the task function. Once the stack has been initialised
-	the	top of stack variable is updated. */
+	the top of stack variable is updated. */
 	#if( portUSING_MPU_WRAPPERS == 1 )
 	{
 		pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
@@ -1515,14 +1616,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
 				}
 
 				/* If the task is in the blocked or suspended list we need do
-				nothing more than change it's priority variable. However, if
+				nothing more than change its priority variable. However, if
 				the task is in a ready list it needs to be removed and placed
 				in the list appropriate to its new priority. */
 				if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
 				{
-					/* The task is currently in its ready list - remove before adding
-					it to it's new ready list.  As we are in a critical section we
-					can do this even if the scheduler is suspended. */
+					/* The task is currently in its ready list - remove before
+					adding it to it's new ready list.  As we are in a critical
+					section we can do this even if the scheduler is suspended. */
 					if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
 					{
 						/* It is known that the task is in its ready list so
@@ -1597,6 +1698,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
 			}
 
 			vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
+
+			#if( configUSE_TASK_NOTIFICATIONS == 1 )
+			{
+				if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
+				{
+					/* The task was blocked to wait for a notification, but is
+					now suspended, so no notification was received. */
+					pxTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
+				}
+			}
+			#endif
 		}
 		taskEXIT_CRITICAL();
 
@@ -1672,7 +1784,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
 			{
 				/* Is it in the suspended list because it is in the	Suspended
 				state, or because is is blocked with no timeout? */
-				if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE )
+				if( listIS_CONTAINED_WITHIN( NULL, &( pxTCB->xEventListItem ) ) != pdFALSE ) /*lint !e961.  The cast is only redundant when NULL is used. */
 				{
 					xReturn = pdTRUE;
 				}
@@ -1716,12 +1828,12 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB )
 				{
 					traceTASK_RESUME( pxTCB );
 
-					/* As we are in a critical section we can access the ready
-					lists even if the scheduler is suspended. */
+					/* The ready list can be accessed even if the scheduler is
+					suspended because this is inside a critical section. */
 					( void ) uxListRemove(  &( pxTCB->xStateListItem ) );
 					prvAddTaskToReadyList( pxTCB );
 
-					/* We may have just resumed a higher priority task. */
+					/* A higher priority task may have just been resumed. */
 					if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
 					{
 						/* This yield may not cause the task just resumed to run,
@@ -1838,9 +1950,9 @@ BaseType_t xReturn;
 		address of the RAM then create the idle task. */
 		vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
 		xIdleTaskHandle = xTaskCreateStatic(	prvIdleTask,
-												"IDLE",
+												configIDLE_TASK_NAME,
 												ulIdleTaskStackSize,
-												( void * ) NULL,
+												( void * ) NULL, /*lint !e961.  The cast is not redundant for all compilers. */
 												( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
 												pxIdleTaskStackBuffer,
 												pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
@@ -1858,7 +1970,8 @@ BaseType_t xReturn;
 	{
 		/* The Idle task is being created using dynamically allocated RAM. */
 		xReturn = xTaskCreate(	prvIdleTask,
-								"IDLE", configMINIMAL_STACK_SIZE,
+								configIDLE_TASK_NAME,
+								configMINIMAL_STACK_SIZE,
 								( void * ) NULL,
 								( tskIDLE_PRIORITY | portPRIVILEGE_BIT ),
 								&xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
@@ -1880,6 +1993,15 @@ BaseType_t xReturn;
 
 	if( xReturn == pdPASS )
 	{
+		/* freertos_tasks_c_additions_init() should only be called if the user
+		definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is
+		the only macro called by the function. */
+		#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
+		{
+			freertos_tasks_c_additions_init();
+		}
+		#endif
+
 		/* Interrupts are turned off here, to ensure a tick does not occur
 		before or during the call to xPortStartScheduler().  The stacks of
 		the created tasks contain a status word with interrupts switched on
@@ -1901,7 +2023,10 @@ BaseType_t xReturn;
 
 		/* If configGENERATE_RUN_TIME_STATS is defined then the following
 		macro must be defined to configure the timer/counter used to generate
-		the run time counter time base. */
+		the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS
+		is set to 0 and the following line fails to build then ensure you do not
+		have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
+		FreeRTOSConfig.h file. */
 		portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();
 
 		/* Setting up the timer tick is hardware specific and thus in the
@@ -2427,7 +2552,7 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
 	BaseType_t xTaskAbortDelay( TaskHandle_t xTask )
 	{
 	TCB_t *pxTCB = ( TCB_t * ) xTask;
-	BaseType_t xReturn = pdFALSE;
+	BaseType_t xReturn;
 
 		configASSERT( pxTCB );
 
@@ -2437,6 +2562,8 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
 			it is actually in the Blocked state. */
 			if( eTaskGetState( xTask ) == eBlocked )
 			{
+				xReturn = pdPASS;
+
 				/* Remove the reference to the task from the blocked list.  An
 				interrupt won't touch the xStateListItem because the
 				scheduler is suspended. */
@@ -2485,10 +2612,10 @@ implementations require configUSE_TICKLESS_IDLE to be set to a value other than
 			}
 			else
 			{
-				mtCOVERAGE_TEST_MARKER();
+				xReturn = pdFAIL;
 			}
 		}
-		xTaskResumeAll();
+		( void ) xTaskResumeAll();
 
 		return xReturn;
 	}
@@ -2510,13 +2637,13 @@ BaseType_t xSwitchRequired = pdFALSE;
 	{
 		/* Minor optimisation.  The tick count cannot change in this
 		block. */
-		const TickType_t xConstTickCount = xTickCount + 1;
+		const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1;
 
 		/* Increment the RTOS tick, switching the delayed and overflowed
 		delayed lists if it wraps to 0. */
 		xTickCount = xConstTickCount;
 
-		if( xConstTickCount == ( TickType_t ) 0U )
+		if( xConstTickCount == ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
 		{
 			taskSWITCH_DELAYED_LISTS();
 		}
@@ -2959,10 +3086,9 @@ BaseType_t xReturn;
 }
 /*-----------------------------------------------------------*/
 
-BaseType_t xTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
+void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem, const TickType_t xItemValue )
 {
 TCB_t *pxUnblockedTCB;
-BaseType_t xReturn;
 
 	/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED.  It is used by
 	the event flags implementation. */
@@ -2985,28 +3111,30 @@ BaseType_t xReturn;
 
 	if( pxUnblockedTCB->uxPriority > pxCurrentTCB->uxPriority )
 	{
-		/* Return true if the task removed from the event list has
-		a higher priority than the calling task.  This allows
-		the calling task to know if it should force a context
-		switch now. */
-		xReturn = pdTRUE;
-
-		/* Mark that a yield is pending in case the user is not using the
-		"xHigherPriorityTaskWoken" parameter to an ISR safe FreeRTOS function. */
+		/* The unblocked task has a priority above that of the calling task, so
+		a context switch is required.  This function is called with the
+		scheduler suspended so xYieldPending is set so the context switch
+		occurs immediately that the scheduler is resumed (unsuspended). */
 		xYieldPending = pdTRUE;
 	}
-	else
-	{
-		xReturn = pdFALSE;
-	}
-
-	return xReturn;
 }
 /*-----------------------------------------------------------*/
 
 void vTaskSetTimeOutState( TimeOut_t * const pxTimeOut )
 {
 	configASSERT( pxTimeOut );
+	taskENTER_CRITICAL();
+	{
+		pxTimeOut->xOverflowCount = xNumOfOverflows;
+		pxTimeOut->xTimeOnEntering = xTickCount;
+	}
+	taskEXIT_CRITICAL();
+}
+/*-----------------------------------------------------------*/
+
+void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut )
+{
+	/* For internal use only as it does not use a critical section. */
 	pxTimeOut->xOverflowCount = xNumOfOverflows;
 	pxTimeOut->xTimeOnEntering = xTickCount;
 }
@@ -3023,6 +3151,7 @@ BaseType_t xReturn;
 	{
 		/* Minor optimisation.  The tick count cannot change in this block. */
 		const TickType_t xConstTickCount = xTickCount;
+		const TickType_t xElapsedTime = xConstTickCount - pxTimeOut->xTimeOnEntering;
 
 		#if( INCLUDE_xTaskAbortDelay == 1 )
 			if( pxCurrentTCB->ucDelayAborted != pdFALSE )
@@ -3055,11 +3184,11 @@ BaseType_t xReturn;
 			was called. */
 			xReturn = pdTRUE;
 		}
-		else if( ( ( TickType_t ) ( xConstTickCount - pxTimeOut->xTimeOnEntering ) ) < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
+		else if( xElapsedTime < *pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
 		{
 			/* Not a genuine timeout. Adjust parameters for time remaining. */
-			*pxTicksToWait -= ( xConstTickCount - pxTimeOut->xTimeOnEntering );
-			vTaskSetTimeOutState( pxTimeOut );
+			*pxTicksToWait -= xElapsedTime;
+			vTaskInternalSetTimeOutState( pxTimeOut );
 			xReturn = pdFALSE;
 		}
 		else
@@ -3136,6 +3265,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
 	/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
 	SCHEDULER IS STARTED. **/
 
+	/* In case a task that has a secure context deletes itself, in which case
+	the idle task is responsible for deleting the task's secure context, if
+	any. */
+	portTASK_CALLS_SECURE_FUNCTIONS();
+
 	for( ;; )
 	{
 		/* See if any tasks have deleted themselves - if so then the idle task
@@ -3212,6 +3346,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
 					configASSERT( xNextTaskUnblockTime >= xTickCount );
 					xExpectedIdleTime = prvGetExpectedIdleTime();
 
+					/* Define the following macro to set xExpectedIdleTime to 0
+					if the application does not want
+					portSUPPRESS_TICKS_AND_SLEEP() to be called. */
+					configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING( xExpectedIdleTime );
+
 					if( xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
 					{
 						traceLOW_POWER_IDLE_BEGIN();
@@ -3369,37 +3508,22 @@ static void prvCheckTasksWaitingTermination( void )
 
 	#if ( INCLUDE_vTaskDelete == 1 )
 	{
-		BaseType_t xListIsEmpty;
+		TCB_t *pxTCB;
 
-		/* ucTasksDeleted is used to prevent vTaskSuspendAll() being called
-		too often in the idle task. */
+		/* uxDeletedTasksWaitingCleanUp is used to prevent vTaskSuspendAll()
+		being called too often in the idle task. */
 		while( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
 		{
-			vTaskSuspendAll();
+			taskENTER_CRITICAL();
 			{
-				xListIsEmpty = listLIST_IS_EMPTY( &xTasksWaitingTermination );
+				pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
+				( void ) uxListRemove( &( pxTCB->xStateListItem ) );
+				--uxCurrentNumberOfTasks;
+				--uxDeletedTasksWaitingCleanUp;
 			}
-			( void ) xTaskResumeAll();
+			taskEXIT_CRITICAL();
 
-			if( xListIsEmpty == pdFALSE )
-			{
-				TCB_t *pxTCB;
-
-				taskENTER_CRITICAL();
-				{
-					pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( ( &xTasksWaitingTermination ) );
-					( void ) uxListRemove( &( pxTCB->xStateListItem ) );
-					--uxCurrentNumberOfTasks;
-					--uxDeletedTasksWaitingCleanUp;
-				}
-				taskEXIT_CRITICAL();
-
-				prvDeleteTCB( pxTCB );
-			}
-			else
-			{
-				mtCOVERAGE_TEST_MARKER();
-			}
+			prvDeleteTCB( pxTCB );
 		}
 	}
 	#endif /* INCLUDE_vTaskDelete */
@@ -3421,25 +3545,6 @@ static void prvCheckTasksWaitingTermination( void )
 		pxTaskStatus->pxStackBase = pxTCB->pxStack;
 		pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;
 
-		#if ( INCLUDE_vTaskSuspend == 1 )
-		{
-			/* If the task is in the suspended list then there is a chance it is
-			actually just blocked indefinitely - so really it should be reported as
-			being in the Blocked state. */
-			if( pxTaskStatus->eCurrentState == eSuspended )
-			{
-				vTaskSuspendAll();
-				{
-					if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
-					{
-						pxTaskStatus->eCurrentState = eBlocked;
-					}
-				}
-				xTaskResumeAll();
-			}
-		}
-		#endif /* INCLUDE_vTaskSuspend */
-
 		#if ( configUSE_MUTEXES == 1 )
 		{
 			pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
@@ -3460,12 +3565,38 @@ static void prvCheckTasksWaitingTermination( void )
 		}
 		#endif
 
-		/* Obtaining the task state is a little fiddly, so is only done if the value
-		of eState passed into this function is eInvalid - otherwise the state is
-		just set to whatever is passed in. */
+		/* Obtaining the task state is a little fiddly, so is only done if the
+		value of eState passed into this function is eInvalid - otherwise the
+		state is just set to whatever is passed in. */
 		if( eState != eInvalid )
 		{
-			pxTaskStatus->eCurrentState = eState;
+			if( pxTCB == pxCurrentTCB )
+			{
+				pxTaskStatus->eCurrentState = eRunning;
+			}
+			else
+			{
+				pxTaskStatus->eCurrentState = eState;
+
+				#if ( INCLUDE_vTaskSuspend == 1 )
+				{
+					/* If the task is in the suspended list then there is a
+					chance it is actually just blocked indefinitely - so really
+					it should be reported as being in the Blocked state. */
+					if( eState == eSuspended )
+					{
+						vTaskSuspendAll();
+						{
+							if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
+							{
+								pxTaskStatus->eCurrentState = eBlocked;
+							}
+						}
+						( void ) xTaskResumeAll();
+					}
+				}
+				#endif /* INCLUDE_vTaskSuspend */
+			}
 		}
 		else
 		{
@@ -3499,7 +3630,7 @@ static void prvCheckTasksWaitingTermination( void )
 
 	static UBaseType_t prvListTasksWithinSingleList( TaskStatus_t *pxTaskStatusArray, List_t *pxList, eTaskState eState )
 	{
-	volatile TCB_t *pxNextTCB, *pxFirstTCB;
+	configLIST_VOLATILE TCB_t *pxNextTCB, *pxFirstTCB;
 	UBaseType_t uxTask = 0;
 
 		if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 )
@@ -3600,7 +3731,7 @@ static void prvCheckTasksWaitingTermination( void )
 			vPortFree( pxTCB->pxStack );
 			vPortFree( pxTCB );
 		}
-		#elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )
+		#elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
 		{
 			/* The task could have been allocated statically or dynamically, so
 			check what was statically allocated before trying to free the
@@ -3622,7 +3753,7 @@ static void prvCheckTasksWaitingTermination( void )
 			{
 				/* Neither the stack nor the TCB were allocated dynamically, so
 				nothing needs to be freed. */
-				configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB	)
+				configASSERT( pxTCB->ucStaticallyAllocated == tskSTATICALLY_ALLOCATED_STACK_AND_TCB	);
 				mtCOVERAGE_TEST_MARKER();
 			}
 		}
@@ -3703,25 +3834,27 @@ TCB_t *pxTCB;
 
 #if ( configUSE_MUTEXES == 1 )
 
-	void vTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
+	BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
 	{
-	TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
+	TCB_t * const pxMutexHolderTCB = ( TCB_t * ) pxMutexHolder;
+	BaseType_t xReturn = pdFALSE;
 
 		/* If the mutex was given back by an interrupt while the queue was
-		locked then the mutex holder might now be NULL. */
+		locked then the mutex holder might now be NULL.  _RB_ Is this still
+		needed as interrupts can no longer use mutexes? */
 		if( pxMutexHolder != NULL )
 		{
 			/* If the holder of the mutex has a priority below the priority of
 			the task attempting to obtain the mutex then it will temporarily
 			inherit the priority of the task attempting to obtain the mutex. */
-			if( pxTCB->uxPriority < pxCurrentTCB->uxPriority )
+			if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
 			{
 				/* Adjust the mutex holder state to account for its new
 				priority.  Only reset the event list item value if the value is
-				not	being used for anything else. */
-				if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
+				not being used for anything else. */
+				if( ( listGET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
 				{
-					listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
+					listSET_LIST_ITEM_VALUE( &( pxMutexHolderTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB->uxPriority ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
 				}
 				else
 				{
@@ -3730,11 +3863,11 @@ TCB_t *pxTCB;
 
 				/* If the task being modified is in the ready state it will need
 				to be moved into a new list. */
-				if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxTCB->uxPriority ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
+				if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
 				{
-					if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
+					if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
 					{
-						taskRESET_READY_PRIORITY( pxTCB->uxPriority );
+						taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
 					}
 					else
 					{
@@ -3742,26 +3875,45 @@ TCB_t *pxTCB;
 					}
 
 					/* Inherit the priority before being moved into the new list. */
-					pxTCB->uxPriority = pxCurrentTCB->uxPriority;
-					prvAddTaskToReadyList( pxTCB );
+					pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
+					prvAddTaskToReadyList( pxMutexHolderTCB );
 				}
 				else
 				{
 					/* Just inherit the priority. */
-					pxTCB->uxPriority = pxCurrentTCB->uxPriority;
+					pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
 				}
 
-				traceTASK_PRIORITY_INHERIT( pxTCB, pxCurrentTCB->uxPriority );
+				traceTASK_PRIORITY_INHERIT( pxMutexHolderTCB, pxCurrentTCB->uxPriority );
+
+				/* Inheritance occurred. */
+				xReturn = pdTRUE;
 			}
 			else
 			{
-				mtCOVERAGE_TEST_MARKER();
+				if( pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority )
+				{
+					/* The base priority of the mutex holder is lower than the
+					priority of the task attempting to take the mutex, but the
+					current priority of the mutex holder is not lower than the
+					priority of the task attempting to take the mutex.
+					Therefore the mutex holder must have already inherited a
+					priority, but inheritance would have occurred if that had
+					not been the case. */
+					xReturn = pdTRUE;
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
 			}
 		}
 		else
 		{
 			mtCOVERAGE_TEST_MARKER();
 		}
+
+		return xReturn;
 	}
 
 #endif /* configUSE_MUTEXES */
@@ -3781,7 +3933,6 @@ TCB_t *pxTCB;
 			interrupt, and if a mutex is given by the holding task then it must
 			be the running state task. */
 			configASSERT( pxTCB == pxCurrentTCB );
-
 			configASSERT( pxTCB->uxMutexesHeld );
 			( pxTCB->uxMutexesHeld )--;
 
@@ -3795,8 +3946,8 @@ TCB_t *pxTCB;
 					/* A task can only have an inherited priority if it holds
 					the mutex.  If the mutex is held by a task then it cannot be
 					given from an interrupt, and if a mutex is given by the
-					holding	task then it must be the running state task.  Remove
-					the	holding task from the ready	list. */
+					holding task then it must be the running state task.  Remove
+					the holding task from the ready list. */
 					if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
 					{
 						taskRESET_READY_PRIORITY( pxTCB->uxPriority );
@@ -3848,6 +3999,108 @@ TCB_t *pxTCB;
 #endif /* configUSE_MUTEXES */
 /*-----------------------------------------------------------*/
 
+#if ( configUSE_MUTEXES == 1 )
+
+	void vTaskPriorityDisinheritAfterTimeout( TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask )
+	{
+	TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder;
+	UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;
+	const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;
+
+		if( pxMutexHolder != NULL )
+		{
+			/* If pxMutexHolder is not NULL then the holder must hold at least
+			one mutex. */
+			configASSERT( pxTCB->uxMutexesHeld );
+
+			/* Determine the priority to which the priority of the task that
+			holds the mutex should be set.  This will be the greater of the
+			holding task's base priority and the priority of the highest
+			priority task that is waiting to obtain the mutex. */
+			if( pxTCB->uxBasePriority < uxHighestPriorityWaitingTask )
+			{
+				uxPriorityToUse = uxHighestPriorityWaitingTask;
+			}
+			else
+			{
+				uxPriorityToUse = pxTCB->uxBasePriority;
+			}
+
+			/* Does the priority need to change? */
+			if( pxTCB->uxPriority != uxPriorityToUse )
+			{
+				/* Only disinherit if no other mutexes are held.  This is a
+				simplification in the priority inheritance implementation.  If
+				the task that holds the mutex is also holding other mutexes then
+				the other mutexes may have caused the priority inheritance. */
+				if( pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld )
+				{
+					/* If a task has timed out because it already holds the
+					mutex it was trying to obtain then it cannot of inherited
+					its own priority. */
+					configASSERT( pxTCB != pxCurrentTCB );
+
+					/* Disinherit the priority, remembering the previous
+					priority to facilitate determining the subject task's
+					state. */
+					traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
+					uxPriorityUsedOnEntry = pxTCB->uxPriority;
+					pxTCB->uxPriority = uxPriorityToUse;
+
+					/* Only reset the event list item value if the value is not
+					being used for anything else. */
+					if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL )
+					{
+						listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+
+					/* If the running task is not the task that holds the mutex
+					then the task that holds the mutex could be in either the
+					Ready, Blocked or Suspended states.  Only remove the task
+					from its current state list if it is in the Ready state as
+					the task's priority is going to change and there is one
+					Ready list per priority. */
+					if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE )
+					{
+						if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
+						{
+							taskRESET_READY_PRIORITY( pxTCB->uxPriority );
+						}
+						else
+						{
+							mtCOVERAGE_TEST_MARKER();
+						}
+
+						prvAddTaskToReadyList( pxTCB );
+					}
+					else
+					{
+						mtCOVERAGE_TEST_MARKER();
+					}
+				}
+				else
+				{
+					mtCOVERAGE_TEST_MARKER();
+				}
+			}
+			else
+			{
+				mtCOVERAGE_TEST_MARKER();
+			}
+		}
+		else
+		{
+			mtCOVERAGE_TEST_MARKER();
+		}
+	}
+
+#endif /* configUSE_MUTEXES */
+/*-----------------------------------------------------------*/
+
 #if ( portCRITICAL_NESTING_IN_TCB == 1 )
 
 	void vTaskEnterCritical( void )
@@ -3937,7 +4190,7 @@ TCB_t *pxTCB;
 #endif /* ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
 /*-----------------------------------------------------------*/
 
-#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
+#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
 
 	void vTaskList( char * pcWriteBuffer )
 	{
@@ -4029,10 +4282,10 @@ TCB_t *pxTCB;
 		}
 	}
 
-#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
+#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */
 /*----------------------------------------------------------*/
 
-#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
+#if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
 
 	void vTaskGetRunTimeStats( char *pcWriteBuffer )
 	{
@@ -4156,7 +4409,7 @@ TCB_t *pxTCB;
 		}
 	}
 
-#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
+#endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */
 /*-----------------------------------------------------------*/
 
 TickType_t uxTaskResetEventItemValue( void )
@@ -4240,7 +4493,7 @@ TickType_t uxReturn;
 				}
 				else
 				{
-					pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
+					pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;
 				}
 			}
 			else
@@ -4315,7 +4568,7 @@ TickType_t uxReturn;
 			blocked state (because a notification was already pending) or the
 			task unblocked because of a notification.  Otherwise the task
 			unblocked because of a timeout. */
-			if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
+			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
 			{
 				/* A notification was not received. */
 				xReturn = pdFALSE;
@@ -4800,8 +5053,24 @@ const TickType_t xConstTickCount = xTickCount;
 	#endif /* INCLUDE_vTaskSuspend */
 }
 
+/* Code below here allows additional code to be inserted into this source file,
+especially where access to file scope functions and data is needed (for example
+when performing module tests). */
 
 #ifdef FREERTOS_MODULE_TEST
 	#include "tasks_test_access_functions.h"
 #endif
 
+
+#if( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 )
+
+	#include "freertos_tasks_c_additions.h"
+
+	static void freertos_tasks_c_additions_init( void )
+	{
+		#ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
+			FREERTOS_TASKS_C_ADDITIONS_INIT();
+		#endif
+	}
+
+#endif
diff --git a/FreeRTOS/Source/timers.c b/FreeRTOS/Source/timers.c
index d4a821a..44d63aa 100644
--- a/FreeRTOS/Source/timers.c
+++ b/FreeRTOS/Source/timers.c
@@ -1,5 +1,5 @@
 /*
-    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
+    FreeRTOS V9.0.1 - Copyright (C) 2017 Real Time Engineers Ltd.
     All rights reserved
 
     VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
@@ -100,6 +100,12 @@ configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
 /* Misc definitions. */
 #define tmrNO_DELAY		( TickType_t ) 0U
 
+/* The name assigned to the timer service task.  This can be overridden by
+defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */
+#ifndef configTIMER_SERVICE_TASK_NAME
+	#define configTIMER_SERVICE_TASK_NAME "Tmr Svc"
+#endif
+
 /* The definition of the timers themselves. */
 typedef struct tmrTimerControl
 {
@@ -158,8 +164,8 @@ typedef struct tmrTimerQueueMessage
 	} u;
 } DaemonTaskMessage_t;
 
-/*lint -e956 A manual analysis and inspection has been used to determine which
-static variables must be declared volatile. */
+/*lint -save -e956 A manual analysis and inspection has been used to determine
+which static variables must be declared volatile. */
 
 /* The list in which active timers are stored.  Timers are referenced in expire
 time order, with the nearest expiry time at the front of the list.  Only the
@@ -173,7 +179,7 @@ PRIVILEGED_DATA static List_t *pxOverflowTimerList;
 PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
 PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;
 
-/*lint +e956 */
+/*lint -restore */
 
 /*-----------------------------------------------------------*/
 
@@ -248,12 +254,12 @@ static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseTy
  * Called after a Timer_t structure has been allocated either statically or
  * dynamically to fill in the structure's members.
  */
-static void prvInitialiseNewTimer(	const char * const pcTimerName,
+static void prvInitialiseNewTimer(	const char * const pcTimerName,			/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 									const TickType_t xTimerPeriodInTicks,
 									const UBaseType_t uxAutoReload,
 									void * const pvTimerID,
 									TimerCallbackFunction_t pxCallbackFunction,
-									Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+									Timer_t *pxNewTimer ) PRIVILEGED_FUNCTION;
 /*-----------------------------------------------------------*/
 
 BaseType_t xTimerCreateTimerTask( void )
@@ -276,7 +282,7 @@ BaseType_t xReturn = pdFAIL;
 
 			vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
 			xTimerTaskHandle = xTaskCreateStatic(	prvTimerTask,
-													"Tmr Svc",
+													configTIMER_SERVICE_TASK_NAME,
 													ulTimerTaskStackSize,
 													NULL,
 													( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
@@ -291,7 +297,7 @@ BaseType_t xReturn = pdFAIL;
 		#else
 		{
 			xReturn = xTaskCreate(	prvTimerTask,
-									"Tmr Svc",
+									configTIMER_SERVICE_TASK_NAME,
 									configTIMER_TASK_STACK_DEPTH,
 									NULL,
 									( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
@@ -311,11 +317,11 @@ BaseType_t xReturn = pdFAIL;
 
 #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
 
-	TimerHandle_t xTimerCreate(	const char * const pcTimerName,
+	TimerHandle_t xTimerCreate(	const char * const pcTimerName,			/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 								const TickType_t xTimerPeriodInTicks,
 								const UBaseType_t uxAutoReload,
 								void * const pvTimerID,
-								TimerCallbackFunction_t pxCallbackFunction ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+								TimerCallbackFunction_t pxCallbackFunction )
 	{
 	Timer_t *pxNewTimer;
 
@@ -343,12 +349,12 @@ BaseType_t xReturn = pdFAIL;
 
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
 
-	TimerHandle_t xTimerCreateStatic(	const char * const pcTimerName,
+	TimerHandle_t xTimerCreateStatic(	const char * const pcTimerName,		/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 										const TickType_t xTimerPeriodInTicks,
 										const UBaseType_t uxAutoReload,
 										void * const pvTimerID,
 										TimerCallbackFunction_t pxCallbackFunction,
-										StaticTimer_t *pxTimerBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+										StaticTimer_t *pxTimerBuffer )
 	{
 	Timer_t *pxNewTimer;
 
@@ -356,7 +362,7 @@ BaseType_t xReturn = pdFAIL;
 		{
 			/* Sanity check that the size of the structure used to declare a
 			variable of type StaticTimer_t equals the size of the real timer
-			structures. */
+			structure. */
 			volatile size_t xSize = sizeof( StaticTimer_t );
 			configASSERT( xSize == sizeof( Timer_t ) );
 		}
@@ -385,12 +391,12 @@ BaseType_t xReturn = pdFAIL;
 #endif /* configSUPPORT_STATIC_ALLOCATION */
 /*-----------------------------------------------------------*/
 
-static void prvInitialiseNewTimer(	const char * const pcTimerName,
+static void prvInitialiseNewTimer(	const char * const pcTimerName,			/*lint !e971 Unqualified char types are allowed for strings and single characters only. */
 									const TickType_t xTimerPeriodInTicks,
 									const UBaseType_t uxAutoReload,
 									void * const pvTimerID,
 									TimerCallbackFunction_t pxCallbackFunction,
-									Timer_t *pxNewTimer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
+									Timer_t *pxNewTimer )
 {
 	/* 0 is not a valid value for xTimerPeriodInTicks. */
 	configASSERT( ( xTimerPeriodInTicks > 0 ) );
@@ -760,7 +766,7 @@ TickType_t xTimeNow;
 			software timer. */
 			pxTimer = xMessage.u.xTimerParameters.pxTimer;
 
-			if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
+			if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE ) /*lint !e961. The cast is only redundant when NULL is passed into the macro. */
 			{
 				/* The timer is in a list, remove it. */
 				( void ) uxListRemove( &( pxTimer->xTimerListItem ) );
@@ -945,10 +951,10 @@ static void prvCheckForValidListAndQueue( void )
 			{
 				/* The timer queue is allocated statically in case
 				configSUPPORT_DYNAMIC_ALLOCATION is 0. */
-				static StaticQueue_t xStaticTimerQueue;
-				static uint8_t ucStaticTimerQueueStorage[ configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ];
+				static StaticQueue_t xStaticTimerQueue; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
+				static uint8_t ucStaticTimerQueueStorage[ ( size_t ) configTIMER_QUEUE_LENGTH * sizeof( DaemonTaskMessage_t ) ]; /*lint !e956 Ok to declare in this manner to prevent additional conditional compilation guards in other locations. */
 
-				xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
+				xTimerQueue = xQueueCreateStatic( ( UBaseType_t ) configTIMER_QUEUE_LENGTH, ( UBaseType_t ) sizeof( DaemonTaskMessage_t ), &( ucStaticTimerQueueStorage[ 0 ] ), &xStaticTimerQueue );
 			}
 			#else
 			{
@@ -991,7 +997,7 @@ Timer_t *pxTimer = ( Timer_t * ) xTimer;
 		/* Checking to see if it is in the NULL list in effect checks to see if
 		it is referenced from either the current or the overflow timer lists in
 		one go, but the logic has to be reversed, hence the '!'. */
-		xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
+		xTimerIsInActiveList = ( BaseType_t ) !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) ); /*lint !e961. Cast is only redundant when NULL is passed into the macro. */
 	}
 	taskEXIT_CRITICAL();
 
diff --git a/README.md b/README.md
index 6f1a381..4c18c40 100644
--- a/README.md
+++ b/README.md
@@ -78,8 +78,8 @@ Current status is alpha quality, actively developed. AP STATION mode (ie wifi cl
 ## Open Source Components
 
 * [FreeRTOS](http://www.freertos.org/) V9.0.0
-* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v1.4.1, modified via the [esp-lwip project](https://github.com/kadamski/esp-lwip) by @kadamski.
-* [newlib](https://github.com/projectgus/newlib-xtensa) v2.2.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
+* [lwIP](http://lwip.wikia.com/wiki/LwIP_Wiki) v2.0.3, with [some modifications](https://github.com/ourairquality/lwip/).
+* [newlib](https://github.com/ourairquality/newlib) v2.5.0, with patches for xtensa support and locking stubs for thread-safe operation on FreeRTOS.
 
 For details of how third party libraries are integrated, [see the wiki page](https://github.com/SuperHouse/esp-open-rtos/wiki/Third-Party-Libraries).
 
diff --git a/common.mk b/common.mk
index b35dbd9..4ece70a 100644
--- a/common.mk
+++ b/common.mk
@@ -160,6 +160,26 @@ endif
 -include $$($(1)_OBJ_FILES:.o=.d)
 endef
 
+# Remove comment lines from libgcc.remove file
+$(BUILD_DIR)libgcc.remove: $(ROOT)lib/libgcc.remove | $(BUILD_DIR)
+	$(Q) grep -v "^#" $< | cat > $@
+
+# Remove unwanted object files listed in libgcc.remove
+$(BUILD_DIR)libgcc.a: $(ROOT)lib/libgcc.a $(BUILD_DIR)libgcc.remove | $(BUILD_DIR)
+	@echo "Removing unwanted objects from $<"
+	$(Q) cat $< > $@
+	$(Q) $(AR) d $@ @$(word 2,$^)
+
+# Remove comment lines from libc.remove file
+$(BUILD_DIR)libc.remove: $(ROOT)libc/libc.remove | $(BUILD_DIR)
+	$(Q) grep -v "^#" $< | cat > $@
+
+# Remove unwanted object files listed in libgcc.remove
+$(BUILD_DIR)libc.a: $(ROOT)libc/xtensa-lx106-elf/lib/libc.a $(BUILD_DIR)libc.remove | $(BUILD_DIR)
+	@echo "Removing unwanted objects from $<"
+	$(Q) cat $< > $@
+	$(Q) $(AR) d $@ @$(word 2,$^)
+
 ## Linking rules for SDK libraries
 ## SDK libraries are preprocessed to:
 # - remove object files named in .remove
@@ -208,9 +228,9 @@ $(foreach component,$(COMPONENTS), 					\
 )
 
 # final linking step to produce .elf
-$(PROGRAM_OUT): $(WHOLE_ARCHIVES) $(COMPONENT_ARS) $(SDK_PROCESSED_LIBS) $(LINKER_SCRIPTS)
+$(PROGRAM_OUT): $(WHOLE_ARCHIVES) $(COMPONENT_ARS) $(BUILD_DIR)libgcc.a $(BUILD_DIR)libc.a $(SDK_PROCESSED_LIBS) $(LINKER_SCRIPTS)
 	$(vecho) "LD $@"
-	$(Q) $(LD) $(LDFLAGS) -Wl,--whole-archive $(WHOLE_ARCHIVES) -Wl,--no-whole-archive -Wl,--start-group $(COMPONENT_ARS) $(LIB_ARGS) $(SDK_LIB_ARGS) -Wl,--end-group -o $@
+	$(Q) $(LD) $(LDFLAGS) -Wl,--whole-archive $(WHOLE_ARCHIVES) -Wl,--no-whole-archive -Wl,--start-group $(COMPONENT_ARS) $(BUILD_DIR)libgcc.a $(BUILD_DIR)libc.a $(LIB_ARGS) $(SDK_LIB_ARGS) -Wl,--end-group -o $@
 
 $(BUILD_DIR) $(FIRMWARE_DIR) $(BUILD_DIR)sdklib:
 	$(Q) mkdir -p $@
diff --git a/core/app_main.c b/core/app_main.c
index 05ad952..fb72cac 100644
--- a/core/app_main.c
+++ b/core/app_main.c
@@ -214,8 +214,8 @@ void IRAM sdk_user_start(void) {
     memcpy(&sdk_g_ic.s, buf32, sizeof(struct sdk_g_ic_saved_st));
 
     // By default, put the sysparam region just below the config sectors at the
-    // top of the flash space
-    sysparam_addr = flash_size - (4 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
+    // top of the flash space, and allowing one extra sector spare.
+    sysparam_addr = flash_size - (5 + DEFAULT_SYSPARAM_SECTORS) * sdk_flashchip.sector_size;
     status = sysparam_init(sysparam_addr, flash_size);
     if (status == SYSPARAM_NOTFOUND) {
         status = sysparam_create_area(sysparam_addr, DEFAULT_SYSPARAM_SECTORS, false);
@@ -236,12 +236,12 @@ void IRAM vApplicationStackOverflowHook(TaskHandle_t task, char *task_name) {
 }
 
 // .text+0x3d8
-void IRAM vApplicationIdleHook(void) {
+void __attribute__((weak)) IRAM vApplicationIdleHook(void) {
     printf("idle %u\n", WDEV.SYS_TIME);
 }
 
 // .text+0x404
-void IRAM vApplicationTickHook(void) {
+void __attribute__((weak)) IRAM vApplicationTickHook(void) {
     printf("tick %u\n", WDEV.SYS_TIME);
 }
 
@@ -311,8 +311,8 @@ static void init_g_ic(void) {
     if (sdk_g_ic.s._unknown310 > 4) {
         sdk_g_ic.s._unknown310 = 4;
     }
-    if (sdk_g_ic.s._unknown1e4._unknown1e4 == 0xffffffff) {
-        bzero(&sdk_g_ic.s._unknown1e4, sizeof(sdk_g_ic.s._unknown1e4));
+    if (sdk_g_ic.s.sta_ssid.ssid_length == 0xffffffff) {
+        bzero(&sdk_g_ic.s.sta_ssid, sizeof(sdk_g_ic.s.sta_ssid));
         bzero(&sdk_g_ic.s.sta_password, sizeof(sdk_g_ic.s.sta_password));
     }
     sdk_g_ic.s.wifi_led_enable = 0;
diff --git a/core/debug_dumps.c b/core/debug_dumps.c
index 6300439..0b18f1a 100644
--- a/core/debug_dumps.c
+++ b/core/debug_dumps.c
@@ -22,6 +22,7 @@
 #include "esp/dport_regs.h"
 #include "espressif/esp_common.h"
 #include "esplibs/libmain.h"
+#include "user_exception.h"
 
 /* Forward declarations */
 static void IRAM fatal_handler_prelude(void);
@@ -33,6 +34,8 @@ static void __attribute__((noinline)) __attribute__((noreturn)) abort_handler_in
 
 static IRAM_DATA fatal_exception_handler_fn fatal_exception_handler_inner = standard_fatal_exception_handler_inner;
 
+static void (*user_exception_handler)(void) = NULL;
+
 /* fatal_exception_handler called from any unhandled user exception
  *
  * (similar to a hard fault on other processor architectures)
@@ -157,6 +160,10 @@ static void IRAM fatal_handler_prelude(void) {
     }
     Cache_Read_Disable();
     Cache_Read_Enable(0, 0, 1);
+
+    if (user_exception_handler != NULL) {
+      user_exception_handler();
+    }
 }
 
 /* Main part of fatal exception handler, is run from flash to save
@@ -230,3 +237,9 @@ static void abort_handler_inner(uint32_t *caller, uint32_t *sp) {
     dump_heapinfo();
     post_crash_reset();
 }
+
+void set_user_exception_handler(void (*fn)(void))
+{
+  user_exception_handler = fn;
+}
+
diff --git a/core/esp_gpio.c b/core/esp_gpio.c
index a3011e1..359f828 100644
--- a/core/esp_gpio.c
+++ b/core/esp_gpio.c
@@ -58,17 +58,17 @@ void gpio_set_pullup(uint8_t gpio_num, bool enabled, bool enabled_during_sleep)
 
 static gpio_interrupt_handler_t gpio_interrupt_handlers[16] = { 0 };
 
-void __attribute__((weak)) IRAM gpio_interrupt_handler(void)
+void __attribute__((weak)) IRAM gpio_interrupt_handler(void *arg)
 {
     uint32_t status_reg = GPIO.STATUS;
     GPIO.STATUS_CLEAR = status_reg;
 
     uint8_t gpio_idx;
-    while((gpio_idx = __builtin_ffs(status_reg)))
+    while ((gpio_idx = __builtin_ffs(status_reg)))
     {
         gpio_idx--;
         status_reg &= ~BIT(gpio_idx);
-        if(FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) {
+        if (FIELD2VAL(GPIO_CONF_INTTYPE, GPIO.CONF[gpio_idx])) {
             gpio_interrupt_handler_t handler = gpio_interrupt_handlers[gpio_idx];
             if (handler) {
                 handler(gpio_idx);
@@ -82,8 +82,8 @@ void gpio_set_interrupt(const uint8_t gpio_num, const gpio_inttype_t int_type, g
     gpio_interrupt_handlers[gpio_num] = handler;
 
     GPIO.CONF[gpio_num] = SET_FIELD(GPIO.CONF[gpio_num], GPIO_CONF_INTTYPE, int_type);
-    if(int_type != GPIO_INTTYPE_NONE) {
-        _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler);
+    if (int_type != GPIO_INTTYPE_NONE) {
+        _xt_isr_attach(INUM_GPIO, gpio_interrupt_handler, NULL);
         _xt_isr_unmask(1<
 #include 
 
-/* Return a random 32-bit number */
-uint32_t hwrand(void)
+/* Return a random 32-bit number.
+ *
+ * This is also used as a substitute for rand() called from
+ * lmac.a:sdk_lmacTxFrame to avoid touching the newlib reent structures within
+ * the NMI and the NMI code needs to be in IRAM.
+ */
+uint32_t IRAM hwrand(void)
 {
     return WDEV.HWRNG;
 }
diff --git a/core/esp_interrupts.c b/core/esp_interrupts.c
index b3aefff..1431499 100644
--- a/core/esp_interrupts.c
+++ b/core/esp_interrupts.c
@@ -7,13 +7,19 @@
  */
 #include 
 
-_xt_isr isr[16];
+typedef struct _xt_isr_entry_ {
+    _xt_isr handler;
+    void *arg;
+} _xt_isr_entry;
+
+_xt_isr_entry isr[16];
 
 bool esp_in_isr;
 
-void IRAM _xt_isr_attach(uint8_t i, _xt_isr func)
+void IRAM _xt_isr_attach(uint8_t i, _xt_isr func, void *arg)
 {
-    isr[i] = func;
+    isr[i].handler = func;
+    isr[i].arg = arg;
 }
 
 /* Generic ISR handler.
@@ -25,17 +31,20 @@ uint16_t IRAM _xt_isr_handler(uint16_t intset)
     esp_in_isr = true;
 
     /* WDT has highest priority (occasional WDT resets otherwise) */
-    if(intset & BIT(INUM_WDT)) {
+    if (intset & BIT(INUM_WDT)) {
         _xt_clear_ints(BIT(INUM_WDT));
-        isr[INUM_WDT]();
+        isr[INUM_WDT].handler(NULL);
         intset -= BIT(INUM_WDT);
     }
 
-    while(intset) {
+    while (intset) {
         uint8_t index = __builtin_ffs(intset) - 1;
         uint16_t mask = BIT(index);
         _xt_clear_ints(mask);
-        isr[index]();
+        _xt_isr handler = isr[index].handler;
+        if (handler) {
+            handler(isr[index].arg);
+        }
         intset -= mask;
     }
 
diff --git a/core/esp_spi.c b/core/esp_spi.c
index 0bda9d2..47dcd66 100644
--- a/core/esp_spi.c
+++ b/core/esp_spi.c
@@ -159,6 +159,22 @@ inline static void _start(uint8_t bus)
     SPI(bus).CMD |= SPI_CMD_USR;
 }
 
+inline static void _store_data(uint8_t bus, const void *data, size_t len)
+{
+    uint8_t words = len / 4;
+    uint8_t tail = len % 4;
+
+    memcpy((void *)SPI(bus).W, data, len - tail);
+
+    if (!tail) return;
+
+    uint32_t last = 0;
+    uint8_t *offs = (uint8_t *)data + len - tail;
+    for (uint8_t i = 0; i < tail; i++)
+        last = last | (offs[i] << (i * 8));
+    SPI(bus).W[words] = last;
+}
+
 inline static uint32_t _swap_bytes(uint32_t value)
 {
     return (value << 24) | ((value << 8) & 0x00ff0000) | ((value >> 8) & 0x0000ff00) | (value >> 24);
@@ -189,7 +205,7 @@ static void _spi_buf_transfer(uint8_t bus, const void *out_data, void *in_data,
     _wait(bus);
     size_t bytes = len * (uint8_t)word_size;
     _set_size(bus, bytes);
-    memcpy((void *)SPI(bus).W, out_data, bytes);
+    _store_data(bus, out_data, bytes);
     _spi_buf_prepare(bus, len, e, word_size);
     _start(bus);
     _wait(bus);
@@ -221,23 +237,36 @@ uint32_t spi_transfer_32(uint8_t bus, uint32_t data)
     return res;
 }
 
-static void _rearm_extras_bit(uint8_t bus, bool arm) {
-
-    if(!_minimal_pins[bus]) return ;
-    static uint8_t status[2] ;
+static void _rearm_extras_bit(uint8_t bus, bool arm)
+{
+    if (!_minimal_pins[bus]) return;
+    static uint8_t status[2];
 
     if (arm)
     {
-        if (status[bus] & 0x01) SPI(bus).USER0 |= (SPI_USER0_ADDR) ;
-        if (status[bus] & 0x02) SPI(bus).USER0 |= (SPI_USER0_COMMAND) ;
-        if (status[bus] & 0x04) SPI(bus).USER0 |= (SPI_USER0_DUMMY | SPI_USER0_MISO);
+        if (status[bus] & 0x01) SPI(bus).USER0 |= (SPI_USER0_ADDR);
+        if (status[bus] & 0x02) SPI(bus).USER0 |= (SPI_USER0_COMMAND);
+        if (status[bus] & 0x04)
+            SPI(bus).USER0 |= (SPI_USER0_DUMMY | SPI_USER0_MISO);
         status[bus] = 0;
     }
     else
     {
-        if (SPI(bus).USER0 & SPI_USER0_ADDR) { SPI(bus).USER0 &= ~(SPI_USER0_ADDR) ; status[bus] |= 0x01 ; }
-        if (SPI(bus).USER0 & SPI_USER0_COMMAND) { SPI(bus).USER0 &= ~(SPI_USER0_COMMAND) ; status[bus] |= 0x02 ; }
-        if (SPI(bus).USER0 & SPI_USER0_DUMMY) { SPI(bus).USER0 &= ~(SPI_USER0_DUMMY | SPI_USER0_MISO); status[bus] |= 0x04 ; }
+        if (SPI(bus).USER0 & SPI_USER0_ADDR)
+        {
+            SPI(bus).USER0 &= ~(SPI_USER0_ADDR);
+            status[bus] |= 0x01;
+        }
+        if (SPI(bus).USER0 & SPI_USER0_COMMAND)
+        {
+            SPI(bus).USER0 &= ~(SPI_USER0_COMMAND);
+            status[bus] |= 0x02;
+        }
+        if (SPI(bus).USER0 & SPI_USER0_DUMMY)
+        {
+            SPI(bus).USER0 &= ~(SPI_USER0_DUMMY | SPI_USER0_MISO);
+            status[bus] |= 0x04;
+        }
     }
 }
 
@@ -254,7 +283,7 @@ size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len
         size_t offset = i * _SPI_BUF_SIZE;
         _spi_buf_transfer(bus, (const uint8_t *)out_data + offset,
             in_data ? (uint8_t *)in_data + offset : NULL, buf_size, e, word_size);
-        if (blocks) _rearm_extras_bit(bus, false) ;
+       _rearm_extras_bit(bus, false);
     }
 
     uint8_t tail = len % buf_size;
@@ -264,41 +293,42 @@ size_t spi_transfer(uint8_t bus, const void *out_data, void *in_data, size_t len
             in_data ? (uint8_t *)in_data + blocks * _SPI_BUF_SIZE : NULL, tail, e, word_size);
     }
 
-    if (blocks) _rearm_extras_bit(bus, true) ;
+    if (blocks) _rearm_extras_bit(bus, true);
     return len;
 }
 
-static void _repeat_send(uint8_t bus, uint32_t* dword,int32_t* repeats,spi_word_size_t size)
+static void _repeat_send(uint8_t bus, uint32_t *dword, int32_t *repeats,
+    spi_word_size_t size)
 {
-    uint8_t i = 0 ;
-    while(*repeats > 0)
+    uint8_t i = 0;
+    while (*repeats > 0)
     {
-        uint16_t bytes_to_transfer = __min(*repeats * size , _SPI_BUF_SIZE);
+        uint16_t bytes_to_transfer = __min(*repeats * size, _SPI_BUF_SIZE);
         _wait(bus);
-        if (i)  _rearm_extras_bit(bus, false) ;
-        _set_size(bus,bytes_to_transfer);
-        for(i = 0; i < (bytes_to_transfer + 3) / 4;i++)
+        if (i) _rearm_extras_bit(bus, false);
+        _set_size(bus, bytes_to_transfer);
+        for (i = 0; i < (bytes_to_transfer + 3) / 4; i++)
             SPI(bus).W[i] = *dword; //need test with memcpy !
         _start(bus);
-        *repeats -= (bytes_to_transfer / size ) ;
+        *repeats -= (bytes_to_transfer / size);
     }
     _wait(bus);
-    _rearm_extras_bit(bus, true) ;
+    _rearm_extras_bit(bus, true);
 }
 
-void spi_repeat_send_8(uint8_t bus, uint8_t data,int32_t repeats)
+void spi_repeat_send_8(uint8_t bus, uint8_t data, int32_t repeats)
 {
     uint32_t dword = data << 24 | data << 16 | data << 8 | data;
-    _repeat_send(bus,&dword,&repeats, SPI_8BIT);
+    _repeat_send(bus, &dword, &repeats, SPI_8BIT);
 }
 
-void spi_repeat_send_16(uint8_t bus, uint16_t data,int32_t repeats)
+void spi_repeat_send_16(uint8_t bus, uint16_t data, int32_t repeats)
 {
     uint32_t dword = data << 16 | data;
-    _repeat_send(bus,&dword,&repeats, SPI_16BIT);
+    _repeat_send(bus, &dword, &repeats, SPI_16BIT);
 }
 
-void spi_repeat_send_32(uint8_t bus, uint32_t data,int32_t repeats)
+void spi_repeat_send_32(uint8_t bus, uint32_t data, int32_t repeats)
 {
-    _repeat_send(bus,&data,&repeats, SPI_32BIT);
+    _repeat_send(bus, &data, &repeats, SPI_32BIT);
 }
diff --git a/core/include/esp/gpio.h b/core/include/esp/gpio.h
index 9187087..85842aa 100644
--- a/core/include/esp/gpio.h
+++ b/core/include/esp/gpio.h
@@ -150,7 +150,7 @@ typedef void (* gpio_interrupt_handler_t)(uint8_t gpio_num);
  *
  *   Example:
  *
- *   void IRAM gpio_interrupt_handler(void) {
+ *   void IRAM gpio_interrupt_handler(void *arg) {
  *        // check GPIO.STATUS
  *        // write GPIO.STATUS_CLEAR
  *        // Do something when GPIO changes
diff --git a/core/include/esp/interrupts.h b/core/include/esp/interrupts.h
index 47594a2..5bdd833 100644
--- a/core/include/esp/interrupts.h
+++ b/core/include/esp/interrupts.h
@@ -35,19 +35,37 @@ typedef enum {
     INUM_TIMER_FRC2 = 10,
 } xt_isr_num_t;
 
-void sdk__xt_int_exit (void);
-void _xt_user_exit (void);
-void sdk__xt_tick_timer_init (void);
-void sdk__xt_timer_int(void);
+void sdk__xt_int_exit(void);
+void _xt_user_exit(void);
+void sdk__xt_tick_timer_init(void);
+void sdk__xt_timer_int(void *);
 void sdk__xt_timer_int1(void);
 
+/* The normal running level is 0.
+ * The system tick isr, timer frc2_isr, sv_isr etc  run at level 1.
+ * Debug exceptions run at level 2?
+ * The wdev nmi runs at level 3.
+ */
 static inline uint32_t _xt_get_intlevel(void)
 {
     uint32_t level;
-    __asm__ volatile("rsr %0, intlevel" : "=a"(level));
-    return level;
+    __asm__ volatile("rsr %0, ps" : "=a"(level));
+    return level & 0xf;
 }
 
+/*
+ * There are conflicting definitions for XCHAL_EXCM_LEVEL. Newlib
+ * defines it to be 1 and xtensa_rtos.h defines it to be 3. Don't want
+ * 3 as that is for the NMI and might want to check that the OS apis
+ * are not entered in level 3. Setting the interrupt level to 3 does
+ * not disable the NMI anyway. So set the level to 2.
+ */
+
+#ifdef XCHAL_EXCM_LEVEL
+#undef XCHAL_EXCM_LEVEL
+#define XCHAL_EXCM_LEVEL 2
+#endif
+
 /* Disable interrupts and return the old ps value, to pass into
    _xt_restore_interrupts later.
 
@@ -68,25 +86,27 @@ static inline void _xt_restore_interrupts(uint32_t new_ps)
     __asm__ volatile ("wsr %0, ps; rsync" :: "a" (new_ps));
 }
 
-/* ESPTODO: the mask/unmask functions aren't thread safe */
-
-static inline void _xt_isr_unmask(uint32_t unmask)
+static inline uint32_t _xt_isr_unmask(uint32_t unmask)
 {
+    uint32_t old_level = _xt_disable_interrupts();
     uint32_t intenable;
     asm volatile ("rsr %0, intenable" : "=a" (intenable));
-    intenable |= unmask;
-    asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
+    asm volatile ("wsr %0, intenable;" :: "a" (intenable | unmask));
+    _xt_restore_interrupts(old_level);
+    return intenable;
 }
 
-static inline void _xt_isr_mask (uint32_t mask)
+static inline uint32_t _xt_isr_mask(uint32_t mask)
 {
+    uint32_t old_level = _xt_disable_interrupts();
     uint32_t intenable;
     asm volatile ("rsr %0, intenable" : "=a" (intenable));
-    intenable &= ~mask;
-    asm volatile ("wsr %0, intenable; esync" :: "a" (intenable));
+    asm volatile ("wsr %0, intenable;" :: "a" (intenable & ~mask));
+    _xt_restore_interrupts(old_level);
+    return intenable;
 }
 
-static inline uint32_t _xt_read_ints (void)
+static inline uint32_t _xt_read_ints(void)
 {
     uint32_t interrupt;
     asm volatile ("rsr %0, interrupt" : "=a" (interrupt));
@@ -98,9 +118,7 @@ static inline void _xt_clear_ints(uint32_t mask)
     asm volatile ("wsr %0, intclear; esync" :: "a" (mask));
 }
 
-typedef void (* _xt_isr)(void);
-/* This function is implemeneted in FreeRTOS port.c at the moment,
-   should be moved or converted to an inline */
-void        _xt_isr_attach (uint8_t i, _xt_isr func);
+typedef void (* _xt_isr)(void *arg);
+void _xt_isr_attach (uint8_t i, _xt_isr func, void *arg);
 
 #endif
diff --git a/core/include/flashchip.h b/core/include/flashchip.h
index c14d4a3..c3edbe4 100644
--- a/core/include/flashchip.h
+++ b/core/include/flashchip.h
@@ -36,4 +36,6 @@ typedef struct {
     uint32_t status_mask;
 } sdk_flashchip_t;
 
+extern sdk_flashchip_t sdk_flashchip;
+
 #endif /* _FLASHCHIP_H */
diff --git a/core/include/sdk_internal.h b/core/include/sdk_internal.h
index 1847eef..a4e21c6 100644
--- a/core/include/sdk_internal.h
+++ b/core/include/sdk_internal.h
@@ -14,25 +14,25 @@
 // 'info' is declared in app_main.o at .bss+0x4
 
 struct sdk_info_st {
-    ip_addr_t softap_ipaddr;    // 0x00
-    ip_addr_t softap_netmask;   // 0x04
-    ip_addr_t softap_gw;        // 0x08
-    ip_addr_t sta_ipaddr;       // 0x0c
-    ip_addr_t sta_netmask;      // 0x10
-    ip_addr_t sta_gw;           // 0x14
+    ip4_addr_t softap_ipaddr;    // 0x00
+    ip4_addr_t softap_netmask;   // 0x04
+    ip4_addr_t softap_gw;        // 0x08
+    ip4_addr_t sta_ipaddr;       // 0x0c
+    ip4_addr_t sta_netmask;      // 0x10
+    ip4_addr_t sta_gw;           // 0x14
     uint8_t softap_mac_addr[6]; // 0x18
     uint8_t sta_mac_addr[6];    // 0x1e
 };
 
 
-struct _unknown_info1 {
+struct wl_channel {
     uint8_t _unknown00;
     uint8_t _unknown01;
     uint8_t _unknown02;
     uint8_t _unknown03;
     uint8_t _unknown04;
     uint8_t _unknown05;
-    uint8_t channel; // eagle_auth_done
+    uint8_t num; // eagle_auth_done
 };
 
 
@@ -83,7 +83,7 @@ struct _unknown_wpa1 {
 };
 
 
-struct sdk_netif_conninfo {
+struct sdk_cnx_node {
     uint8_t mac_addr[6];
     uint8_t _unknown07[2];
 
@@ -98,17 +98,19 @@ struct sdk_netif_conninfo {
 
     uint32_t _unknown1c[23];
 
-    struct _unknown_info1 *_unknown78; // eagle_auth_done
+    struct wl_channel *channel; // 0x78 eagle_auth_done
 
     uint32_t _unknown7c[8];
 
     uint16_t _unknown9c; // ieee80211_hostap. increases by one one each timer func called.
     uint16_t _unknown9e;
 
-    uint32_t _unknowna0[18];
+    uint32_t _unknowna0[17];
 
-    int8_t _unknowne8; //
-    int8_t _unknowne9; // ppInstallKey
+    void *_unknowne4;
+
+    uint8_t _unknowne8; //
+    uint8_t _unknowne9; // ppInstallKey
     int8_t _unknownea;
     int8_t _unknowneb;
 
@@ -128,9 +130,9 @@ struct sdk_g_ic_netif_info {
     uint32_t _unknown48;     // 0x48
     uint8_t _unknown4c;      // 0x4c
     uint8_t _unknown4d[59];  // 0x4d - 0x88
-    struct sdk_netif_conninfo *_unknown88;  // 0x88
+    struct sdk_cnx_node *_unknown88;  // 0x88
     uint32_t _unknown8c;     // 0x8c
-    struct sdk_netif_conninfo *conninfo[6]; // 0x90 - 0xa8
+    struct sdk_cnx_node *cnx_nodes[6]; // 0x90 - 0xa8
     uint8_t _unknowna8[12];  // 0xa8 - 0xb4
     struct _unknown_softap1 *_unknownb4;
     uint8_t statusb8;        // 0xb8 (arg of sta_status_set)
@@ -206,10 +208,9 @@ struct sdk_g_ic_volatile_st {
 };
 
 
-struct sdk_g_ic_unk0_st {
-    uint16_t _unknown1e4;  // sdk_wpa_config_profile
-    uint16_t _unknown1e6;  // sdk_wpa_config_profile
-    uint8_t sta_ssid[32];  // 0x1e8 Station ssid. Null terminated string.
+struct sdk_g_ic_ssid_with_length {
+    uint32_t ssid_length;  // 0x1e4 sdk_wpa_config_profile
+    uint8_t ssid[32];  // 0x1e8 Station ssid. Null terminated string.
 };
 
 // This is the portion of g_ic which is loaded/saved to the flash ROM, and thus
@@ -224,7 +225,8 @@ struct sdk_g_ic_saved_st {
     uint8_t wifi_led_gpio;
     uint8_t wifi_led_state;  // 0 or 1.
 
-    struct sdk_g_ic_unk0_st _unknown1e4;
+    // Current station ap config ssid and length.
+    struct sdk_g_ic_ssid_with_length sta_ssid; // 0x1e4
 
     uint8_t _unknown208;
     uint8_t _unknown209; // sdk_wpa_config_profile
@@ -260,7 +262,7 @@ struct sdk_g_ic_saved_st {
     uint8_t _unknown30d; // result of ieee80211_chan2ieee
     uint8_t _unknown30e;
     uint8_t _unknown30f;
-    uint8_t _unknown310; // count of entries in the softap conninfo array, less two.
+    uint8_t _unknown310; // count of entries in the softap cnx_node array, less two.
 
     uint8_t _unknown311[3];
 
@@ -320,7 +322,7 @@ struct esf_buf {
 _Static_assert(sizeof(struct sdk_info_st) == 0x24, "info_st is the wrong size!");
 _Static_assert(offsetof(struct sdk_info_st, sta_mac_addr) == 0x1e, "bad struct");
 
-_Static_assert(offsetof(struct _unknown_info1, channel) == 0x06, "bad struct");
+_Static_assert(offsetof(struct wl_channel, num) == 0x06, "bad struct");
 
 _Static_assert(sizeof(struct _unknown_softap2) == 0xcc, "_unknown_softap2 is the wrong size!");
 _Static_assert(offsetof(struct _unknown_softap2, _unknownb8) == 0xb8, "bad struct");
@@ -331,8 +333,8 @@ _Static_assert(offsetof(struct _unknown_softap1, _unknown18) == 0x18, "bad struc
 _Static_assert(sizeof(struct _unknown_wpa1) == 0x4c, "_unknown_wpa1 is the wrong size!");
 _Static_assert(offsetof(struct _unknown_wpa1, _unknown48) == 0x48, "bad struct");
 
-_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown78) == 0x78, "bad struct");
-_Static_assert(offsetof(struct sdk_netif_conninfo, _unknown108) == 0x108, "bad struct");
+_Static_assert(offsetof(struct sdk_cnx_node, channel) == 0x78, "bad struct");
+_Static_assert(offsetof(struct sdk_cnx_node, _unknown108) == 0x108, "bad struct");
 
 _Static_assert(offsetof(struct sdk_g_ic_netif_info, started) == 0xbb, "bad struct");
 
@@ -340,7 +342,7 @@ _Static_assert(sizeof(struct sdk_g_ic_volatile_st) == 0x1d8, "sdk_g_ic_volatile_
 _Static_assert(offsetof(struct sdk_g_ic_volatile_st, _unknown1d5) == 0x1d5, "bad struct");
 
 _Static_assert(sizeof(struct sdk_g_ic_saved_st) == 0x370, "sdk_g_ic_saved_st is the wrong size!");
-_Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown1e4) == 0x1e4 - 0x1d8, "bad struct");
+_Static_assert(offsetof(struct sdk_g_ic_saved_st, sta_ssid) == 0x1e4 - 0x1d8, "bad struct");
 _Static_assert(offsetof(struct sdk_g_ic_saved_st, _unknown546) == 0x546 - 0x1d8, "bad struct");
 
 _Static_assert(sizeof(struct sdk_g_ic_st) == 0x548, "sdk_g_ic_st is the wrong size!");
@@ -357,21 +359,16 @@ _Static_assert(offsetof(struct esf_buf, length) == 0x16, "bad struct");
 // ieee80211_output_pbuf and perhaps elsewhere. The value is just passed through
 // lwip and and not used by lwip so just ensure this slot is at the expected
 // offset.
-_Static_assert(offsetof(struct netif, state) == 28, "netif->state offset wrong!");
+_Static_assert(offsetof(struct netif, state) == 4, "netif->state offset wrong!");
 
 // Some sdk uses of netif->hwaddr have been converted to source code, but many
 // remain, but the content of this slot should not change in future versions of
-// lwip, so just ensure it is at the expected offset.
-_Static_assert(offsetof(struct netif, hwaddr) == 41, "netif->hwaddr offset wrong!");
+// lwip, so just ensure it is at the expected offset. Note the sdk binary
+// libraries have been patched to move this offset from 41 to 42 to keep it
+// 16-bit aligned to keep lwip v2 happy.
+_Static_assert(offsetof(struct netif, hwaddr) == 8, "netif->hwaddr offset wrong!");
 
-// Most sdk uses of the netif->flags have been converted to source code. One
-// known sdk binary read of the flags remains in wl_cnx.o:sdk_cnx_sta_leave
-// which checks the NETIF_FLAG_DHCP flag. The NETIF_FLAG_DHCP has been removed
-// in lwip v2, so some lwip hacks are needed to handle this for now until
-// wl_cnx.o is converted so source code too.
-_Static_assert(offsetof(struct netif, flags) == 47, "netif->flags offset wrong!");
-
-_Static_assert(offsetof(struct pbuf, eb) == 16, "pbuf->eb offset wrong!");
+_Static_assert(offsetof(struct pbuf, esf_buf) == 16, "pbuf->esf_buf offset wrong!");
 
 
 /// Misc.
diff --git a/extras/spiffs/esp_spiffs_flash.h b/core/include/spiflash.h
similarity index 76%
rename from extras/spiffs/esp_spiffs_flash.h
rename to core/include/spiflash.h
index abfe864..f8397db 100644
--- a/extras/spiffs/esp_spiffs_flash.h
+++ b/core/include/spiflash.h
@@ -21,14 +21,14 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#ifndef __ESP_SPIFFS_FLASH_H__
-#define __ESP_SPIFFS_FLASH_H__
+#ifndef __SPIFLASH_H__
+#define __SPIFLASH_H__
 
 #include 
+#include 
 #include "common_macros.h"
 
-#define ESP_SPIFFS_FLASH_OK        0
-#define ESP_SPIFFS_FLASH_ERROR     1
+#define SPI_FLASH_SECTOR_SIZE      4096
 
 /**
  * Read data from SPI flash.
@@ -37,9 +37,9 @@
  * @param buf Buffer to read to. Doesn't have to be aligned.
  * @param size Size of data to read. Buffer size must be >= than data size.
  *
- * @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR
+ * @return true if success, otherwise false
  */
-uint32_t IRAM esp_spiffs_flash_read(uint32_t addr, uint8_t *buf, uint32_t size);
+bool IRAM spiflash_read(uint32_t addr, uint8_t *buf, uint32_t size);
 
 /**
  * Write data to SPI flash.
@@ -48,17 +48,17 @@ uint32_t IRAM esp_spiffs_flash_read(uint32_t addr, uint8_t *buf, uint32_t size);
  * @param buf Buffer of data to write to flash. Doesn't have to be aligned.
  * @param size Size of data to write. Buffer size must be >= than data size.
  *
- * @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR
+ * @return true if success, otherwise false
  */
-uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size);
+bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size);
 
 /**
  * Erase a sector.
  *
  * @param addr Address of sector to erase. Must be sector aligned.
  *
- * @return ESP_SPIFFS_FLASH_OK or ESP_SPIFFS_FLASH_ERROR
+ * @return true if success, otherwise false
  */
-uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr);
+bool IRAM spiflash_erase_sector(uint32_t addr);
 
-#endif  // __ESP_SPIFFS_FLASH_H__
+#endif  // __SPIFLASH_H__
diff --git a/core/include/sysparam.h b/core/include/sysparam.h
index 60084be..130bd05 100644
--- a/core/include/sysparam.h
+++ b/core/include/sysparam.h
@@ -119,7 +119,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr);
  *  you reformat the area currently being used, you will also need to call
  *  sysparam_init() again afterward before you will be able to continue using
  *  it.
- */ 
+ */
 sysparam_status_t sysparam_create_area(uint32_t base_addr, uint16_t num_sectors, bool force);
 
 /** Get the start address and size of the currently active sysparam area
@@ -180,24 +180,20 @@ sysparam_status_t sysparam_compact();
  */
 sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *actual_length, bool *is_binary);
 
-/** Get the value associated with a key (static buffers only)
+/** Get the value associated with a key (static value buffer)
  *
  *  This performs the same function as sysparam_get_data() but without
- *  performing any memory allocations.  It can thus be used before the heap has
- *  been configured or in other cases where using the heap would be a problem
- *  (i.e. in an OOM handler, etc).  It requires that the caller pass in a
- *  suitably sized buffer for the value to be read (if the supplied buffer is
- *  not large enough, the returned value will be truncated and the full
- *  required length will be returned in `actual_length`).
- *
- *  NOTE: In addition to being large enough for the value, the supplied buffer
- *  must also be at least as large as the length of the key being requested.
- *  If it is not, an error will be returned.
+ *  allocating memory for the result value.  It can thus be used before the heap
+ *  has been configured or in other cases where using the heap would be a
+ *  problem (i.e. in an OOM handler, etc).  It requires that the caller pass in
+ *  a suitably sized buffer for the value to be read (if the supplied buffer is
+ *  not large enough, the returned value will be truncated and the full required
+ *  length will be returned in `actual_length`).
  *
  *  @param[in]  key            Key name (zero-terminated string)
- *  @param[in]  buffer         Pointer to a buffer to hold the returned value
- *  @param[in]  buffer_size    Length of the supplied buffer in bytes
- *  @param[out] actual_length  pointer to a location to hold the actual length
+ *  @param[in]  dest           Pointer to a buffer to hold the returned value.
+ *  @param[in]  dest_size      Length of the supplied buffer in bytes.
+ *  @param[out] actual_length  Pointer to a location to hold the actual length
  *                             of the data which was associated with the key
  *                             (may be NULL).
  *  @param[out] is_binary      Pointer to a bool to hold whether the returned
@@ -210,10 +206,10 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
  *  @retval ::SYSPARAM_ERR_CORRUPT  Sysparam region has bad/corrupted data
  *  @retval ::SYSPARAM_ERR_IO       I/O error reading/writing flash
  */
-sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, size_t buffer_size, size_t *actual_length, bool *is_binary);
+sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *dest, size_t dest_size, size_t *actual_length, bool *is_binary);
 
 /** Get the string value associated with a key
- * 
+ *
  *  This routine can be used if you know that the value in a key will (or at
  *  least should) be a string.  It will return a zero-terminated char buffer
  *  containing the value retrieved.
@@ -240,9 +236,10 @@ sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, siz
 sysparam_status_t sysparam_get_string(const char *key, char **destptr);
 
 /** Get the int32_t value associated with a key
- * 
+ *
  *  This routine can be used if you know that the value in a key will (or at
- *  least should) be an int32_t value.
+ *  least should) be an int32_t value. This is done without allocating any
+ *  memory.
  *
  *  Note: If the status result is anything other than ::SYSPARAM_OK, the value
  *  in `result` is not changed.  This means it is possible to set a default
@@ -266,7 +263,8 @@ sysparam_status_t sysparam_get_int32(const char *key, int32_t *result);
 /** Get the int8_t value associated with a key
  *
  *  This routine can be used if you know that the value in a key will (or at
- *  least should) be a uint8_t binary value.
+ *  least should) be a uint8_t binary value. This is done without allocating any
+ *  memory.
  *
  *  Note: If the status result is anything other than ::SYSPARAM_OK, the value
  *  in `result` is not changed.  This means it is possible to set a default
@@ -288,7 +286,7 @@ sysparam_status_t sysparam_get_int32(const char *key, int32_t *result);
 sysparam_status_t sysparam_get_int8(const char *key, int8_t *result);
 
 /** Get the boolean value associated with a key
- * 
+ *
  *  This routine can be used if you know that the value in a key will (or at
  *  least should) be a boolean setting.  It will read the specified value as a
  *  text string and attempt to parse it as a boolean value.
@@ -320,7 +318,7 @@ sysparam_status_t sysparam_get_bool(const char *key, bool *result);
  *
  *  The supplied value can be any data, up to 255 bytes in length.  If `value`
  *  is NULL or `value_len` is 0, this is treated as a request to delete any
- *  current entry matching `key`.
+ *  current entry matching `key`. This is done without allocating any memory.
  *
  *  If `binary` is true, the data will be considered binary (unprintable) data,
  *  and this will be annotated in the saved entry.  This does not affect the
@@ -368,7 +366,8 @@ sysparam_status_t sysparam_set_string(const char *key, const char *value);
 /** Set a key's value as a number
  *
  *  Write an int32_t binary value to the specified key. This does the inverse of
- *  the sysparam_get_int32() function.
+ *  the sysparam_get_int32() function. This is done without allocating any
+ *  memory.
  *
  *  @param[in] key        Key name (zero-terminated string)
  *  @param[in] value      Value to set
@@ -386,10 +385,8 @@ sysparam_status_t sysparam_set_int32(const char *key, int32_t value);
 /** Set a key's value as a number
  *
  *  Write an int8_t binary value to the specified key. This does the inverse of
- *  the sysparam_get_int8() function.
- *
- *  Note that if the key already contains a value which parses to the same
- *  boolean (true/false) value, it is left unchanged.
+ *  the sysparam_get_int8() function. This is done without allocating any
+ *  memory.
  *
  *  @param[in] key        Key name (zero-terminated string)
  *  @param[in] value      Value to set
diff --git a/core/include/user_exception.h b/core/include/user_exception.h
new file mode 100644
index 0000000..abb027a
--- /dev/null
+++ b/core/include/user_exception.h
@@ -0,0 +1,9 @@
+/* Allows the user to set their own exception handler. */
+
+#ifndef _USER_EXCEPTION_H
+#define _USER_EXCEPTION_H
+
+void set_user_exception_handler(void (*fn)(void));
+
+#endif
+
diff --git a/core/newlib_syscalls.c b/core/newlib_syscalls.c
index 146a010..d095ba9 100644
--- a/core/newlib_syscalls.c
+++ b/core/newlib_syscalls.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 
 extern void *xPortSupervisorStackPointer;
 
@@ -135,6 +136,14 @@ int _stat_r(struct _reent *r, const char *pathname, void *buf);
 __attribute__((weak, alias("syscall_returns_enosys"))) 
 off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence);
 
+__attribute__((weak, alias("_gettimeofday_r")))
+int _gettimeofday_r _PARAMS ((struct _reent *r, struct timeval *now, void *p)) {
+  now->tv_sec = 0;
+  now->tv_usec = 0;
+  errno = ENOSYS;
+  return -1;
+}
+
 /* Generic stub for any newlib syscall that fails with errno ENOSYS
    ("Function not implemented") and a return value equivalent to
    (int)-1. */
diff --git a/extras/spiffs/esp_spiffs_flash.c b/core/spiflash.c
similarity index 71%
rename from extras/spiffs/esp_spiffs_flash.c
rename to core/spiflash.c
index f0a6049..764db11 100644
--- a/extras/spiffs/esp_spiffs_flash.c
+++ b/core/spiflash.c
@@ -21,12 +21,13 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-#include "esp_spiffs_flash.h"
-#include "flashchip.h"
-#include "espressif/spi_flash.h"
-#include "FreeRTOS.h"
-#include "esp/rom.h"
-#include "esp/spi_regs.h"
+#include "include/spiflash.h"
+
+#include "include/flashchip.h"
+#include "include/esp/rom.h"
+#include "include/esp/spi_regs.h"
+
+#include 
 #include 
 
 /**
@@ -52,25 +53,6 @@
 #define SPI_READ_MAX_SIZE   60
 
 
-/**
- * Copy unaligned data to 4-byte aligned destination buffer.
- *
- * @param words Number of 4-byte words to write.
- *
- * @see unaligned_memcpy.S
- */
-void memcpy_unaligned_src(volatile uint32_t *dst, uint8_t *src, uint8_t words);
-
-/**
- * Copy 4-byte aligned source data to unaligned destination buffer.
- *
- * @param bytes Number of byte to copy to dst.
- *
- * @see unaligned_memcpy.S
- */
-void memcpy_unaligned_dst(uint8_t *dst, volatile uint32_t *src, uint8_t bytes);
-
-
 /**
  * Low level SPI flash write. Write block of data up to 64 bytes.
  */
@@ -86,7 +68,9 @@ static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr,
 
     SPI(0).ADDR = (addr & 0x00FFFFFF) | (size << 24);
 
-    memcpy_unaligned_src(SPI(0).W, buf, words);
+    memcpy((void*)SPI(0).W, buf, words<<2);
+
+    __asm__ volatile("memw");
 
     SPI_write_enable(chip);
 
@@ -97,16 +81,16 @@ static inline void IRAM spi_write_data(sdk_flashchip_t *chip, uint32_t addr,
 /**
  * Write a page of flash. Data block should not cross page boundary.
  */
-static uint32_t IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr,
+static bool IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_addr,
     uint8_t *buf, uint32_t size)
 {
     // check if block to write doesn't cross page boundary
     if (flashchip->page_size < size + (dest_addr % flashchip->page_size)) {
-        return ESP_SPIFFS_FLASH_ERROR;
+        return false;
     }
 
     if (size < 1) {
-        return ESP_SPIFFS_FLASH_OK;
+        return true;
     }
 
     while (size >= SPI_WRITE_MAX_SIZE) {
@@ -117,58 +101,58 @@ static uint32_t IRAM spi_write_page(sdk_flashchip_t *flashchip, uint32_t dest_ad
         buf += SPI_WRITE_MAX_SIZE;
 
         if (size < 1) {
-            return ESP_SPIFFS_FLASH_OK;
+            return true;
         }
     }
 
     spi_write_data(flashchip, dest_addr, buf, size);
 
-    return ESP_SPIFFS_FLASH_OK;
+    return true;
 }
 
 /**
  * Split block of data into pages and write pages.
  */
-static uint32_t IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size)
+static bool IRAM spi_write(uint32_t addr, uint8_t *dst, uint32_t size)
 {
     if (sdk_flashchip.chip_size < (addr + size)) {
-        return ESP_SPIFFS_FLASH_ERROR;
+        return false;
     }
 
     uint32_t write_bytes_to_page = sdk_flashchip.page_size -
         (addr % sdk_flashchip.page_size);  // TODO: place for optimization
 
     if (size < write_bytes_to_page) {
-        if (spi_write_page(&sdk_flashchip, addr, dst, size)) {
-            return ESP_SPIFFS_FLASH_ERROR;
+        if (!spi_write_page(&sdk_flashchip, addr, dst, size)) {
+            return false;
         }
     } else {
-        if (spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
-            return ESP_SPIFFS_FLASH_ERROR;
+        if (!spi_write_page(&sdk_flashchip, addr, dst, write_bytes_to_page)) {
+            return false;
         }
 
         uint32_t offset = write_bytes_to_page;
         uint32_t pages_to_write = (size - offset) / sdk_flashchip.page_size;
-        for (uint8_t i = 0; i != pages_to_write; i++) {
-            if (spi_write_page(&sdk_flashchip, addr + offset,
+        for (uint32_t i = 0; i < pages_to_write; i++) {
+            if (!spi_write_page(&sdk_flashchip, addr + offset,
                         dst + offset, sdk_flashchip.page_size)) {
-                return ESP_SPIFFS_FLASH_ERROR;
+                return false;
             }
             offset += sdk_flashchip.page_size;
         }
 
-        if (spi_write_page(&sdk_flashchip, addr + offset,
+        if (!spi_write_page(&sdk_flashchip, addr + offset,
                     dst + offset, size - offset)) {
-            return ESP_SPIFFS_FLASH_ERROR;
+            return false;
         }
     }
 
-    return ESP_SPIFFS_FLASH_OK;
+    return true;
 }
 
-uint32_t IRAM esp_spiffs_flash_write(uint32_t addr, uint8_t *buf, uint32_t size)
+bool IRAM spiflash_write(uint32_t addr, uint8_t *buf, uint32_t size)
 {
-    uint32_t result = ESP_SPIFFS_FLASH_ERROR;
+    bool result = false;
 
     if (buf) {
         vPortEnterCritical();
@@ -197,21 +181,23 @@ static inline void IRAM read_block(sdk_flashchip_t *chip, uint32_t addr,
 
     while (SPI(0).CMD) {};
 
-    memcpy_unaligned_dst(buf, SPI(0).W, size);
+    __asm__ volatile("memw");
+
+    memcpy(buf, (const void*)SPI(0).W, size);
 }
 
 /**
  * Read SPI flash data. Data region doesn't need to be page aligned.
  */
-static inline uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
+static inline bool IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
         uint8_t *dst, uint32_t size)
 {
     if (size < 1) {
-        return ESP_SPIFFS_FLASH_OK;
+        return true;
     }
 
     if ((addr + size) > flashchip->chip_size) {
-        return ESP_SPIFFS_FLASH_ERROR;
+        return false;
     }
 
     while (size >= SPI_READ_MAX_SIZE) {
@@ -225,12 +211,12 @@ static inline uint32_t IRAM read_data(sdk_flashchip_t *flashchip, uint32_t addr,
         read_block(flashchip, addr, dst, size);
     }
 
-    return ESP_SPIFFS_FLASH_OK;
+    return true;
 }
 
-uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size)
+bool IRAM spiflash_read(uint32_t dest_addr, uint8_t *buf, uint32_t size)
 {
-    uint32_t result = ESP_SPIFFS_FLASH_ERROR;
+    bool result = false;
 
     if (buf) {
         vPortEnterCritical();
@@ -245,14 +231,14 @@ uint32_t IRAM esp_spiffs_flash_read(uint32_t dest_addr, uint8_t *buf, uint32_t s
     return result;
 }
 
-uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr)
+bool IRAM spiflash_erase_sector(uint32_t addr)
 {
     if ((addr + sdk_flashchip.sector_size) > sdk_flashchip.chip_size) {
-        return ESP_SPIFFS_FLASH_ERROR;
+        return false;
     }
 
     if (addr & 0xFFF) {
-        return ESP_SPIFFS_FLASH_ERROR;
+        return false;
     }
 
     vPortEnterCritical();
@@ -269,5 +255,5 @@ uint32_t IRAM esp_spiffs_flash_erase_sector(uint32_t addr)
     Cache_Read_Enable(0, 0, 1);
     vPortExitCritical();
 
-    return ESP_SPIFFS_FLASH_OK;
+    return true;
 }
diff --git a/core/sysparam.c b/core/sysparam.c
index 084a2be..27471a0 100644
--- a/core/sysparam.c
+++ b/core/sysparam.c
@@ -8,14 +8,12 @@
 #include 
 #include 
 #include 
-#include 
+#include "spiflash.h"
+#include "flashchip.h"
 #include 
 #include "FreeRTOS.h"
 #include "semphr.h"
 
-//TODO: make this properly threadsafe
-//TODO: reduce stack usage
-
 /* The "magic" value that indicates the start of a sysparam region in flash.
  */
 #define SYSPARAM_MAGIC 0x70524f45 // "EORp" in little-endian
@@ -33,11 +31,14 @@
  */
 #define SCAN_BUFFER_SIZE 8 // words
 
-/* The size of the temporary buffer used for reading back and verifying data
- * written to flash.  Making this larger will make the write-and-verify
- * operation slightly faster, but will use more heap during writes
+/* The size in words of the buffer used for reading keys when searching for a
+ * match, for reading payloads to check if the value has changed, and reading
+ * back from the flash to verify writes. Will work well if big enough for
+ * commonly used keys, and must be at least one word. Stack allocated so not too
+ * large!
  */
-#define VERIFY_BUF_SIZE 64
+#define BOUNCE_BUFFER_WORDS 3
+#define BOUNCE_BUFFER_SIZE (BOUNCE_BUFFER_WORDS * sizeof(uint32_t))
 
 /* Size of region/entry headers.  These should not normally need tweaking (and
  * will probably require some code changes if they are tweaked).
@@ -76,14 +77,16 @@
 /******************************* Useful Macros *******************************/
 
 #define ROUND_TO_WORD_BOUNDARY(x) (((x) + 3) & 0xfffffffc)
-#define ENTRY_SIZE(payload_len) (ENTRY_HEADER_SIZE + ROUND_TO_WORD_BOUNDARY(payload_len))
+#define ENTRY_SIZE(payload_len) (ENTRY_HEADER_SIZE + payload_len)
 
 #define max(x, y) ((x) > (y) ? (x) : (y))
 #define min(x, y) ((x) < (y) ? (x) : (y))
 
 #define debug(level, format, ...) if (SYSPARAM_DEBUG >= (level)) { printf("%s" format "\n", "sysparam: ", ## __VA_ARGS__); }
 
-#define CHECK_FLASH_OP(x) do { int __x = (x); if ((__x) != SPI_FLASH_RESULT_OK) { debug(1, "FLASH ERR: %d", __x); return SYSPARAM_ERR_IO; } } while (0);
+#define CHECK_FLASH_OP(x) do { bool __x = (x); if (!(__x)) { \
+        debug(1, "FLASH ERR: %d", __x); return SYSPARAM_ERR_IO; \
+    } } while (0);
 
 /********************* Internal datatypes and structures *********************/
 
@@ -119,50 +122,28 @@ static struct {
 
 /***************************** Internal routines *****************************/
 
-static inline IRAM sysparam_status_t _do_write(uint32_t addr, const void *data, size_t data_size) {
-    CHECK_FLASH_OP(sdk_spi_flash_write(addr, (void*) data, data_size));
-    return SYSPARAM_OK;
-}
+static sysparam_status_t _write_and_verify(uint32_t addr, const void *data, size_t data_size) {
+    uint8_t bounce[BOUNCE_BUFFER_SIZE];
 
-static inline IRAM sysparam_status_t _do_verify(uint32_t addr, const void *data, void *buffer, size_t len) {
-    CHECK_FLASH_OP(sdk_spi_flash_read(addr, buffer, len));
-    if (memcmp(data, buffer, len)) {
-        return SYSPARAM_ERR_IO;
+    for (int i = 0; i < data_size; i += BOUNCE_BUFFER_SIZE) {
+        size_t count = min(data_size - i, BOUNCE_BUFFER_SIZE);
+        memcpy(bounce, data + i, count);
+        CHECK_FLASH_OP(spiflash_write(addr + i, bounce, count));
+        CHECK_FLASH_OP(spiflash_read(addr + i, bounce, count));
+        if (memcmp(data + i, bounce, count) != 0) {
+            debug(1, "Flash write (@ 0x%08x) verify failed!", addr);
+            return SYSPARAM_ERR_IO;
+        }
     }
     return SYSPARAM_OK;
 }
 
-/*FIXME: Eventually, this should probably be implemented down at the SPI flash library layer, where it can just compare bytes/words straight from the SPI hardware buffer instead of allocating a whole separate temp buffer, reading chunks into that, and then doing a memcmp.. */
-static IRAM sysparam_status_t _write_and_verify(uint32_t addr, const void *data, size_t data_size) {
-    int i;
-    size_t count;
-    sysparam_status_t status = SYSPARAM_OK;
-    uint8_t *verify_buf = malloc(VERIFY_BUF_SIZE);
-
-    if (!verify_buf) return SYSPARAM_ERR_NOMEM;
-    do {
-        status = _do_write(addr, data, data_size);
-        if (status != SYSPARAM_OK) break;
-        for (i = 0; i < data_size; i += VERIFY_BUF_SIZE) {
-            count = min(data_size - i, VERIFY_BUF_SIZE);
-            status = _do_verify(addr + i, data + i, verify_buf, count);
-            if (status != SYSPARAM_OK) {
-                debug(1, "Flash write (@ 0x%08x) verify failed!", addr);
-                break;
-            }
-        }
-    } while (false);
-    free(verify_buf);
-    return status;
-}
-
 /** Erase the sectors of a region */
 static sysparam_status_t _format_region(uint32_t addr, uint16_t num_sectors) {
-    uint16_t sector = addr / sdk_flashchip.sector_size;
     int i;
 
     for (i = 0; i < num_sectors; i++) {
-        CHECK_FLASH_OP(sdk_spi_flash_erase_sector(sector + i));
+        CHECK_FLASH_OP(spiflash_erase_sector(addr + (i * SPI_FLASH_SECTOR_SIZE)));
     }
     return SYSPARAM_OK;
 }
@@ -212,7 +193,7 @@ static sysparam_status_t init_write_context(struct sysparam_context *ctx) {
     memset(ctx, 0, sizeof(*ctx));
     ctx->addr = _sysparam_info.end_addr;
     debug(3, "read entry header @ 0x%08x", ctx->addr);
-    CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE));
+    CHECK_FLASH_OP(spiflash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE));
     return SYSPARAM_OK;
 }
 
@@ -238,7 +219,10 @@ static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint16_t matc
                 // workaround is to make sure that the next write operation
                 // will always start with a compaction, which will leave off
                 // the invalid data at the end and fix the issue going forward.
-                debug(1, "Encountered entry with invalid length (0x%04x) @ 0x%08x (region end is 0x%08x).  Truncating entries.", ctx->entry.len, ctx->addr, _sysparam_info.end_addr);
+                debug(1, "Encountered entry with invalid length (0x%04x) @ 0x%08x (region end is 0x%08x).  Truncating entries.",
+                        ctx->entry.len,
+                        ctx->addr, _sysparam_info.end_addr);
+
                 _sysparam_info.force_compact = true;
                 break;
             }
@@ -251,7 +235,7 @@ static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint16_t matc
         }
 
         debug(3, "read entry header @ 0x%08x", ctx->addr);
-        CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE));
+        CHECK_FLASH_OP(spiflash_read(ctx->addr, (void*) &ctx->entry, ENTRY_HEADER_SIZE));
         debug(3, "  idflags = 0x%04x", ctx->entry.idflags);
         if (ctx->entry.idflags == 0xffff) {
             // 0xffff is never a valid id field, so this means we've hit the
@@ -295,17 +279,39 @@ static sysparam_status_t _find_entry(struct sysparam_context *ctx, uint16_t matc
 }
 
 /** Read the payload from the current entry pointed to by `ctx` */
+
 static inline sysparam_status_t _read_payload(struct sysparam_context *ctx, uint8_t *buffer, size_t buffer_size) {
-    debug(3, "read payload (%d) @ 0x%08x", min(buffer_size, ctx->entry.len), ctx->addr);
-    CHECK_FLASH_OP(sdk_spi_flash_read(ctx->addr + ENTRY_HEADER_SIZE, (void*) buffer, min(buffer_size, ctx->entry.len)));
+    uint32_t addr = ctx->addr + ENTRY_HEADER_SIZE;
+    size_t size = min(buffer_size, ctx->entry.len);
+    debug(3, "read payload (%d) @ 0x%08x", size, addr);
+
+    CHECK_FLASH_OP(spiflash_read(addr, buffer, buffer_size));
+
+    return SYSPARAM_OK;
+}
+
+static inline sysparam_status_t _compare_payload(struct sysparam_context *ctx, uint8_t *value, size_t size) {
+    debug(3, "compare payload (%d) @ 0x%08x", size, ctx->addr);
+    if (ctx->entry.len != size) return SYSPARAM_NOTFOUND;
+    uint32_t bounce[BOUNCE_BUFFER_WORDS];
+    uint32_t addr = ctx->addr + ENTRY_HEADER_SIZE;
+    int i;
+    for (i = 0; i < size; i += BOUNCE_BUFFER_SIZE) {
+        int len = min(size - i, BOUNCE_BUFFER_SIZE);
+        CHECK_FLASH_OP(spiflash_read(addr + i, (void*)bounce, len));
+        if (memcmp(value + i, bounce, len)) {
+            // Mismatch.
+            return SYSPARAM_NOTFOUND;
+        }
+    }
     return SYSPARAM_OK;
 }
 
 /** Find the entry corresponding to the specified key name */
-static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key, uint16_t key_len, uint8_t *buffer) {
+static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key, uint16_t key_len) {
     sysparam_status_t status;
 
-    debug(3, "find key: %s", key ? key : "(null)");
+    debug(3, "find key len %d: %s", key_len, key ? key : "(null)");
     while (true) {
         // Find the next key entry
         status = _find_entry(ctx, ENTRY_ID_ANY, false);
@@ -316,12 +322,12 @@ static sysparam_status_t _find_key(struct sysparam_context *ctx, const char *key
             break;
         }
         if (ctx->entry.len == key_len) {
-            status = _read_payload(ctx, buffer, key_len);
-            if (status < 0) return status;
-            if (!memcmp(key, buffer, key_len)) {
+            status = _compare_payload(ctx, (uint8_t *)key, key_len);
+            if (status == SYSPARAM_OK) {
                 // We have a match
                 break;
             }
+            if (status != SYSPARAM_NOTFOUND) return status;
             debug(3, "entry payload does not match");
         } else {
             debug(3, "key length (%d) does not match (%d)", ctx->entry.len, key_len);
@@ -394,13 +400,11 @@ static inline sysparam_status_t _delete_entry(uint32_t addr) {
 
     debug(2, "Deleting entry @ 0x%08x", addr);
     debug(3, "read entry header @ 0x%08x", addr);
-    CHECK_FLASH_OP(sdk_spi_flash_read(addr, (void*) &entry, ENTRY_HEADER_SIZE));
+    CHECK_FLASH_OP(spiflash_read(addr, (uint8_t*) &entry, ENTRY_HEADER_SIZE));
     // Set the ID to zero to mark it as "deleted"
     entry.idflags &= ~ENTRY_FLAG_ALIVE;
     debug(3, "write entry header @ 0x%08x", addr);
-    CHECK_FLASH_OP(sdk_spi_flash_write(addr, (void*) &entry, ENTRY_HEADER_SIZE));
-
-    return SYSPARAM_OK;
+    return _write_and_verify(addr, &entry, ENTRY_HEADER_SIZE);
 }
 
 /** Compact the current region, removing all deleted/unused entries, and write
@@ -424,7 +428,11 @@ static sysparam_status_t _compact_params(struct sysparam_context *ctx, int *key_
     uint16_t binary_flag;
     uint16_t num_sectors = _sysparam_info.region_size / sdk_flashchip.sector_size;
 
-    debug(1, "compacting region (current size %d, expect to recover %d%s bytes)...", _sysparam_info.end_addr - _sysparam_info.cur_base, ctx ? ctx->compactable : 0, (ctx && ctx->unused_keys > 0) ? "+ (unused keys present)" : "");
+    debug(1, "compacting region (current size %d, expect to recover %d%s bytes)...",
+            _sysparam_info.end_addr - _sysparam_info.cur_base,
+            ctx ? ctx->compactable : 0,
+            (ctx && ctx->unused_keys > 0) ? "+ (unused keys present)" : "");
+
     status = _format_region(new_base, num_sectors);
     if (status < 0) return status;
     status = sysparam_iter_start(&iter);
@@ -505,7 +513,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr) {
         top_addr = base_addr + sdk_flashchip.sector_size;
     }
     for (addr0 = base_addr; addr0 < top_addr; addr0 += sdk_flashchip.sector_size) {
-        CHECK_FLASH_OP(sdk_spi_flash_read(addr0, (void*) &header0, REGION_HEADER_SIZE));
+        CHECK_FLASH_OP(spiflash_read(addr0, (void*) &header0, REGION_HEADER_SIZE));
         if (header0.magic == SYSPARAM_MAGIC) {
             // Found a starting point...
             break;
@@ -523,7 +531,7 @@ sysparam_status_t sysparam_init(uint32_t base_addr, uint32_t top_addr) {
     } else {
         addr1 = addr0 + num_sectors * sdk_flashchip.sector_size;
     }
-    CHECK_FLASH_OP(sdk_spi_flash_read(addr1, (void*) &header1, REGION_HEADER_SIZE));
+    CHECK_FLASH_OP(spiflash_read(addr1, (uint8_t*) &header1, REGION_HEADER_SIZE));
 
     if (header1.magic == SYSPARAM_MAGIC) {
         // Yay! Found the other one.  Sanity-check it..
@@ -600,7 +608,7 @@ sysparam_status_t sysparam_create_area(uint32_t base_addr, uint16_t num_sectors,
         // we're not going to be clobbering something else important.
         for (addr = base_addr; addr < base_addr + region_size * 2; addr += SCAN_BUFFER_SIZE) {
             debug(3, "read %d words @ 0x%08x", SCAN_BUFFER_SIZE, addr);
-            CHECK_FLASH_OP(sdk_spi_flash_read(addr, buffer, SCAN_BUFFER_SIZE * 4));
+            CHECK_FLASH_OP(spiflash_read(addr, (uint8_t*)buffer, SCAN_BUFFER_SIZE * 4));
             for (i = 0; i < SCAN_BUFFER_SIZE; i++) {
                 if (buffer[i] != 0xffffffff) {
                     // Uh oh, not empty.
@@ -655,70 +663,79 @@ sysparam_status_t sysparam_get_data(const char *key, uint8_t **destptr, size_t *
     sysparam_status_t status;
     size_t key_len = strlen(key);
     uint8_t *buffer;
-    uint8_t *newbuf;
-   
-    if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
 
-    buffer = malloc(key_len + 2);
-    if (!buffer) return SYSPARAM_ERR_NOMEM;
-    do {
-        _init_context(&ctx);
-        status = _find_key(&ctx, key, key_len, buffer);
-        if (status != SYSPARAM_OK) break;
+    xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
 
-        // Find the associated value
-        status = _find_value(&ctx, ctx.entry.idflags);
-        if (status != SYSPARAM_OK) break;
-
-        newbuf = realloc(buffer, ctx.entry.len + 1);
-        if (!newbuf) {
-            status = SYSPARAM_ERR_NOMEM;
-            break;
-        }
-        buffer = newbuf;
-        status = _read_payload(&ctx, buffer, ctx.entry.len);
-        if (status != SYSPARAM_OK) break;
-
-        // Zero-terminate the result, just in case (doesn't hurt anything for
-        // non-string data, and can avoid nasty mistakes if the caller wants to
-        // interpret the result as a string).
-        buffer[ctx.entry.len] = 0;
-
-        *destptr = buffer;
-        if (actual_length) *actual_length = ctx.entry.len;
-        if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
-        return SYSPARAM_OK;
-    } while (false);
-
-    free(buffer);
     if (actual_length) *actual_length = 0;
+
+    if (!_sysparam_info.cur_base) {
+        status = SYSPARAM_ERR_NOINIT;
+        goto done;
+    }
+
+    _init_context(&ctx);
+    status = _find_key(&ctx, key, key_len);
+    if (status != SYSPARAM_OK) goto done;
+
+    // Find the associated value
+    status = _find_value(&ctx, ctx.entry.idflags);
+    if (status != SYSPARAM_OK) goto done;
+
+    buffer = malloc(ctx.entry.len + 1);
+    if (!buffer) {
+        status = SYSPARAM_ERR_NOMEM;
+        goto done;
+    }
+
+    status = _read_payload(&ctx, buffer, ctx.entry.len);
+    if (status != SYSPARAM_OK) {
+        free(buffer);
+        goto done;
+    }
+
+    // Zero-terminate the result, just in case (doesn't hurt anything for
+    // non-string data, and can avoid nasty mistakes if the caller wants to
+    // interpret the result as a string).
+    buffer[ctx.entry.len] = 0;
+
+    *destptr = buffer;
+    if (actual_length) *actual_length = ctx.entry.len;
+    if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
+    status = SYSPARAM_OK;
+
+ done:
+    xSemaphoreGive(_sysparam_info.sem);
     return status;
 }
 
-sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *buffer, size_t buffer_size, size_t *actual_length, bool *is_binary) {
+sysparam_status_t sysparam_get_data_static(const char *key, uint8_t *dest, size_t dest_size, size_t *actual_length, bool *is_binary) {
     struct sysparam_context ctx;
     sysparam_status_t status = SYSPARAM_OK;
     size_t key_len = strlen(key);
 
-    if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
-
-    // Supplied buffer must be at least as large as the key, or 2 bytes,
-    // whichever is larger.
-    if (buffer_size < max(key_len, 2)) return SYSPARAM_ERR_NOMEM;
+    xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
 
     if (actual_length) *actual_length = 0;
 
+    if (!_sysparam_info.cur_base) {
+        status = SYSPARAM_ERR_NOINIT;
+        goto done;
+    }
+
     _init_context(&ctx);
-    status = _find_key(&ctx, key, key_len, buffer);
-    if (status != SYSPARAM_OK) return status;
+    status = _find_key(&ctx, key, key_len);
+    if (status != SYSPARAM_OK) goto done;
     status = _find_value(&ctx, ctx.entry.idflags);
-    if (status != SYSPARAM_OK) return status;
-    status = _read_payload(&ctx, buffer, buffer_size);
-    if (status != SYSPARAM_OK) return status;
+    if (status != SYSPARAM_OK) goto done;
+    status = _read_payload(&ctx, dest, dest_size);
+    if (status != SYSPARAM_OK) goto done;
 
     if (actual_length) *actual_length = ctx.entry.len;
     if (is_binary) *is_binary = (bool)(ctx.entry.idflags & ENTRY_FLAG_BINARY);
-    return SYSPARAM_OK;
+
+ done:
+    xSemaphoreGive(_sysparam_info.sem);
+    return status;
 }
 
 sysparam_status_t sysparam_get_string(const char *key, char **destptr) {
@@ -741,63 +758,82 @@ sysparam_status_t sysparam_get_string(const char *key, char **destptr) {
 }
 
 sysparam_status_t sysparam_get_int32(const char *key, int32_t *result) {
-    char *buffer;
-    char *endptr;
     int32_t value;
+    size_t actual_length;
+    bool is_binary;
     sysparam_status_t status;
 
-    status = sysparam_get_string(key, &buffer);
+    status = sysparam_get_data_static(key, (uint8_t *)&value, sizeof(int32_t),
+                                      &actual_length, &is_binary);
     if (status != SYSPARAM_OK) return status;
-    value = strtol(buffer, &endptr, 0);
-    if (*endptr) {
-        // There was extra crap at the end of the string.
-        free(buffer);
+    if (!is_binary || actual_length != sizeof(int32_t))
         return SYSPARAM_PARSEFAILED;
-    }
-
     *result = value;
-    free(buffer);
-    return SYSPARAM_OK;
+    return status;
 }
 
 sysparam_status_t sysparam_get_int8(const char *key, int8_t *result) {
-    int32_t value;
+    int8_t value;
+    size_t actual_length;
+    bool is_binary;
     sysparam_status_t status;
 
-    status = sysparam_get_int32(key, &value);
-    if (status == SYSPARAM_OK) {
-        *result = value;
-    }
+    status = sysparam_get_data_static(key, (uint8_t *)&value, sizeof(int8_t),
+                                      &actual_length, &is_binary);
+    if (status != SYSPARAM_OK) return status;
+    if (!is_binary || actual_length != sizeof(int8_t))
+        return SYSPARAM_PARSEFAILED;
+    *result = value;
     return status;
 }
 
 sysparam_status_t sysparam_get_bool(const char *key, bool *result) {
-    char *buffer;
+    const size_t buf_size = 8;
+    char buf[buf_size + 1];  // extra byte for zero termination
+    size_t data_len = 0;
+    bool binary = false;
     sysparam_status_t status;
 
-    status = sysparam_get_string(key, &buffer);
+    status = sysparam_get_data_static(key, (uint8_t*)buf,
+            buf_size, &data_len, &binary);
+
     if (status != SYSPARAM_OK) return status;
     do {
-        if (!strcasecmp(buffer, "y")    ||
-            !strcasecmp(buffer, "yes")  ||
-            !strcasecmp(buffer, "t")    ||
-            !strcasecmp(buffer, "true") ||
-            !strcmp(buffer, "1")) {
+        if (binary) {
+            if (data_len == 1) {  // int8 value
+                uint8_t value;
+                memcpy(&value, buf, sizeof(value));
+                *result = value ? true : false;
+            } else if (data_len == 4) {  // int32 value
+                uint32_t value;
+                memcpy(&value, buf, sizeof(value));
+                *result = value ? true : false;
+            } else {
+                status = SYSPARAM_PARSEFAILED;
+            }
+            break;
+        }
+        buf[data_len] = 0;
+
+        if (!strcasecmp(buf, "y")    ||
+            !strcasecmp(buf, "yes")  ||
+            !strcasecmp(buf, "t")    ||
+            !strcasecmp(buf, "true") ||
+            !strcmp(buf, "1")) {
                 *result = true;
                 break;
         }
-        if (!strcasecmp(buffer, "n")     ||
-            !strcasecmp(buffer, "no")    ||
-            !strcasecmp(buffer, "f")     ||
-            !strcasecmp(buffer, "false") ||
-            !strcmp(buffer, "0")) {
+        if (!strcasecmp(buf, "n")     ||
+            !strcasecmp(buf, "no")    ||
+            !strcasecmp(buf, "f")     ||
+            !strcasecmp(buf, "false") ||
+            !strcmp(buf, "0")) {
                 *result = false;
                 break;
         }
         status = SYSPARAM_PARSEFAILED;
     } while (0);
 
-    free(buffer);
     return status;
 }
 
@@ -806,48 +842,30 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
     struct sysparam_context write_ctx;
     sysparam_status_t status = SYSPARAM_OK;
     uint16_t key_len = strlen(key);
-    uint8_t *buffer;
-    uint8_t *newbuf;
     size_t free_space;
     size_t needed_space;
-    bool free_value = false;
     int key_id = -1;
     uint32_t old_value_addr = 0;
     uint16_t binary_flag;
-   
-    if (!_sysparam_info.cur_base) return SYSPARAM_ERR_NOINIT;
+
     if (!key_len) return SYSPARAM_ERR_BADVALUE;
     if (key_len > MAX_KEY_LEN) return SYSPARAM_ERR_BADVALUE;
     if (value_len > MAX_VALUE_LEN) return SYSPARAM_ERR_BADVALUE;
 
-    xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
-
     if (!value) value_len = 0;
 
     debug(1, "updating value for '%s' (%d bytes)", key, value_len);
-    if (value_len && ((intptr_t)value & 0x3)) {
-        // The passed value isn't word-aligned.  This will be a problem later
-        // when calling `sdk_spi_flash_write`, so make a word-aligned copy.
-        buffer = malloc(value_len);
-        if (!buffer) {
-            status = SYSPARAM_ERR_NOMEM;
-            goto done;
-        }
-        memcpy(buffer, value, value_len);
-        value = buffer;
-        free_value = true;
-    }
-    // Create a working buffer for `_find_key` to use.
-    buffer = malloc(key_len);
-    if (!buffer) {
-        if (free_value) free((void *)value);
-        status = SYSPARAM_ERR_NOMEM;
+
+    xSemaphoreTake(_sysparam_info.sem, portMAX_DELAY);
+
+    if (!_sysparam_info.cur_base) {
+        status = SYSPARAM_ERR_NOINIT;
         goto done;
     }
 
     do {
         _init_context(&ctx);
-        status = _find_key(&ctx, key, key_len, buffer);
+        status = _find_key(&ctx, key, key_len);
         if (status == SYSPARAM_OK) {
             // Key already exists, see if there's a current value.
             key_id = ctx.entry.idflags & ENTRY_MASK_ID;
@@ -862,24 +880,17 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
 
         if (value_len) {
             if (old_value_addr) {
-                if ((ctx.entry.idflags & ENTRY_FLAG_BINARY) == binary_flag && ctx.entry.len == value_len) {
+                if ((ctx.entry.idflags & ENTRY_FLAG_BINARY) == binary_flag &&
+                    ctx.entry.len == value_len) {
                     // Are we trying to write the same value that's already there?
-                    if (value_len > key_len) {
-                        newbuf = realloc(buffer, value_len);
-                        if (!newbuf) {
-                            status = SYSPARAM_ERR_NOMEM;
-                            break;
-                        }
-                        buffer = newbuf;
-                    }
-                    status = _read_payload(&ctx, buffer, value_len);
-                    if (status < 0) break;
-                    if (!memcmp(buffer, value, value_len)) {
+                    status = _compare_payload(&ctx, (uint8_t *)value, value_len);
+                    if (status == SYSPARAM_OK) {
                         // Yup, it's a match! No need to do anything further,
                         // just leave the current value as-is.
                         status = SYSPARAM_OK;
                         break;
                     }
+                    if (status != SYSPARAM_NOTFOUND) goto done;
                 }
 
                 // Since we will be deleting the old value (if any) make sure
@@ -981,9 +992,6 @@ sysparam_status_t sysparam_set_data(const char *key, const uint8_t *value, size_
         debug(1, "New addr is 0x%08x (%d bytes remaining)", _sysparam_info.end_addr, _sysparam_info.cur_base + _sysparam_info.region_size - _sysparam_info.end_addr);
     } while (false);
 
-    if (free_value) free((void *)value);
-    free(buffer);
-
  done:
     xSemaphoreGive(_sysparam_info.sem);
 
@@ -995,15 +1003,11 @@ sysparam_status_t sysparam_set_string(const char *key, const char *value) {
 }
 
 sysparam_status_t sysparam_set_int32(const char *key, int32_t value) {
-    uint8_t buffer[12];
-    int len;
-    
-    len = snprintf((char *)buffer, 12, "%d", value);
-    return sysparam_set_data(key, buffer, len, false);
+    return sysparam_set_data(key, (const uint8_t *)&value, sizeof(value), true);
 }
 
 sysparam_status_t sysparam_set_int8(const char *key, int8_t value) {
-    return sysparam_set_int32(key, value);
+    return sysparam_set_data(key, (const uint8_t *)&value, sizeof(value), true);
 }
 
 sysparam_status_t sysparam_set_bool(const char *key, bool value) {
@@ -1043,7 +1047,6 @@ sysparam_status_t sysparam_iter_start(sysparam_iter_t *iter) {
 }
 
 sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
-    uint8_t buffer[2];
     sysparam_status_t status;
     size_t required_len;
     struct sysparam_context *ctx = iter->ctx;
@@ -1052,7 +1055,7 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
     char *newbuf;
 
     while (true) {
-        status = _find_key(ctx, NULL, 0, buffer);
+        status = _find_key(ctx, NULL, 0);
         if (status != SYSPARAM_OK) return status;
         memcpy(&value_ctx, ctx, sizeof(value_ctx));
 
@@ -1060,7 +1063,7 @@ sysparam_status_t sysparam_iter_next(sysparam_iter_t *iter) {
         if (status < 0) return status;
         if (status == SYSPARAM_NOTFOUND) continue;
 
-        key_space = ROUND_TO_WORD_BOUNDARY(ctx->entry.len + 1);
+        key_space = ctx->entry.len + 1;
         required_len = key_space + value_ctx.entry.len + 1;
         if (required_len > iter->bufsize) {
             newbuf = realloc(iter->key, required_len);
diff --git a/examples/access_point/access_point.c b/examples/access_point/access_point.c
index f8fcd50..52c622f 100644
--- a/examples/access_point/access_point.c
+++ b/examples/access_point/access_point.c
@@ -48,7 +48,7 @@ void user_init(void)
     };
     sdk_wifi_softap_set_config(&ap_config);
 
-    ip_addr_t first_client_ip;
+    ip4_addr_t first_client_ip;
     IP4_ADDR(&first_client_ip, 172, 16, 0, 2);
     dhcpserver_start(&first_client_ip, 4);
 
@@ -65,14 +65,14 @@ static void telnetTask(void *pvParameters)
     printf("Status monitor: Failed to allocate socket.\r\n");
     return;
   }
-  netconn_bind(nc, IP_ADDR_ANY, TELNET_PORT);
+  netconn_bind(nc, IP_ANY_TYPE, TELNET_PORT);
   netconn_listen(nc);
 
   while(1) {
     struct netconn *client = NULL;
     err_t err = netconn_accept(nc, &client);
 
-    if ( err != ERR_OK ) {
+    if (err != ERR_OK) {
       if(client)
 	netconn_delete(client);
       continue;
@@ -88,9 +88,8 @@ static void telnetTask(void *pvParameters)
     netconn_write(client, buf, strlen(buf), NETCONN_COPY);
     snprintf(buf, sizeof(buf), "Free heap %d bytes\r\n", (int)xPortGetFreeHeapSize());
     netconn_write(client, buf, strlen(buf), NETCONN_COPY);
-    snprintf(buf, sizeof(buf), "Your address is %d.%d.%d.%d\r\n\r\n",
-             ip4_addr1(&client_addr), ip4_addr2(&client_addr),
-             ip4_addr3(&client_addr), ip4_addr4(&client_addr));
+    char abuf[40];
+    snprintf(buf, sizeof(buf), "Your address is %s\r\n\r\n", ipaddr_ntoa_r(&client_addr, abuf, sizeof(abuf)));
     netconn_write(client, buf, strlen(buf), NETCONN_COPY);
     netconn_delete(client);
   }
diff --git a/examples/ad770x/Makefile b/examples/ad770x/Makefile
new file mode 100644
index 0000000..f102848
--- /dev/null
+++ b/examples/ad770x/Makefile
@@ -0,0 +1,4 @@
+PROGRAM = ad770x
+EXTRA_COMPONENTS = extras/ad770x
+#ESPBAUD = 460800
+include ../../common.mk
diff --git a/examples/ad770x/main.c b/examples/ad770x/main.c
new file mode 100644
index 0000000..2a021cc
--- /dev/null
+++ b/examples/ad770x/main.c
@@ -0,0 +1,49 @@
+/*
+ * Example of using AD7705/AD7706 driver
+ *
+ * Part of esp-open-rtos
+ * Copyright (C) 2017 Ruslan V. Uss 
+ * BSD Licensed as described in the file LICENSE
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define CS_PIN 2
+#define AIN_CHANNEL 0 // AIN1+,AIN1- for AD7705
+
+static const ad770x_params_t dev = {
+    .cs_pin = CS_PIN,
+    .master_clock = AD770X_MCLK_4_9152MHz, // 4.9152 MHz
+    .bipolar = false,                      // Unipolar mode
+    .gain = AD770X_GAIN_1,                 // No gain
+    .update_rate = AD770X_RATE_50          // 50 Hz output update rate
+};
+
+void user_init(void)
+{
+    uart_set_baud(0, 115200);
+    printf("SDK version:%s\n", sdk_system_get_sdk_version());
+
+    while (ad770x_init(&dev, AIN_CHANNEL) != 0)
+    {
+        printf("Cannot initialize AD7705\n");
+        vTaskDelay(500 / portTICK_PERIOD_MS);
+    }
+
+    while (true)
+    {
+        // wait for data
+        while (!ad770x_data_ready(&dev, AIN_CHANNEL)) {}
+
+        // Read result
+        uint16_t raw = ad770x_raw_adc_value(&dev, AIN_CHANNEL);
+
+        printf("Raw ADC value: %d\n", raw);
+
+        vTaskDelay(500 / portTICK_PERIOD_MS);
+    }
+}
diff --git a/examples/ads1115_test/main.c b/examples/ads1115_test/main.c
index 8065f04..5c0c4db 100644
--- a/examples/ads1115_test/main.c
+++ b/examples/ads1115_test/main.c
@@ -17,6 +17,7 @@
 // Connect ADDR pin to GND
 #define ADDR ADS111X_ADDR_GND
 
+#define I2C_BUS 0
 #define SCL_PIN 5
 #define SDA_PIN 4
 
@@ -28,23 +29,27 @@ void user_init(void)
     uart_set_baud(0, 115200);
     printf("SDK version:%s\n", sdk_system_get_sdk_version());
 
-    i2c_init(SCL_PIN, SDA_PIN);
+    i2c_dev_t dev = {
+        .addr = ADDR,
+        .bus = I2C_BUS,
+    };
+    i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
 
-    ads111x_set_mode(ADDR, ADS111X_MODE_CONTUNOUS);
-    ads111x_set_data_rate(ADDR, ADS111X_DATA_RATE_32);
+    ads111x_set_mode(&dev, ADS111X_MODE_CONTUNOUS);
+    ads111x_set_data_rate(&dev, ADS111X_DATA_RATE_32);
 
-    ads111x_set_input_mux(ADDR, ADS111X_MUX_0_GND);
-    ads111x_set_gain(ADDR, GAIN);
+    ads111x_set_input_mux(&dev, ADS111X_MUX_0_GND);
+    ads111x_set_gain(&dev, GAIN);
 
     float gain_val = ads111x_gain_values[GAIN];
 
     while (true)
     {
         // wait for conversion end
-        while (ads111x_busy(ADDR)) {}
+        while (ads111x_busy(&dev)) {}
 
         // Read result
-        int16_t raw = ads111x_get_value(ADDR);
+        int16_t raw = ads111x_get_value(&dev);
 
         float voltage = gain_val / ADS111X_MAX_VALUE * raw;
 
diff --git a/examples/aws_iot/ssl_connection.h b/examples/aws_iot/ssl_connection.h
index b8d1bf1..5113701 100644
--- a/examples/aws_iot/ssl_connection.h
+++ b/examples/aws_iot/ssl_connection.h
@@ -4,7 +4,7 @@
 // this must be ahead of any mbedtls header files so the local mbedtls/config.h can be properly referenced
 #include "mbedtls/config.h"
 
-#include "mbedtls/net.h"
+#include "mbedtls/net_sockets.h"
 #include "mbedtls/debug.h"
 #include "mbedtls/ssl.h"
 #include "mbedtls/entropy.h"
diff --git a/examples/bh1750/Makefile b/examples/bh1750/Makefile
new file mode 100644
index 0000000..5abb97a
--- /dev/null
+++ b/examples/bh1750/Makefile
@@ -0,0 +1,3 @@
+PROGRAM=bh1750_example
+EXTRA_COMPONENTS = extras/i2c extras/bh1750
+include ../../common.mk
diff --git a/examples/bh1750/bh1750_example.c b/examples/bh1750/bh1750_example.c
new file mode 100644
index 0000000..b75115c
--- /dev/null
+++ b/examples/bh1750/bh1750_example.c
@@ -0,0 +1,44 @@
+#include 
+
+#include "espressif/esp_common.h"
+#include "esp/uart.h"
+
+#include "FreeRTOS.h"
+#include "task.h"
+
+#include "i2c/i2c.h"
+#include "bh1750/bh1750.h"
+
+#define SCL_PIN 5
+#define SDA_PIN 4
+#define I2C_BUS 0
+
+static void measure(void *pvParameters)
+{
+    i2c_dev_t dev = {
+        .addr = BH1750_ADDR_LO,
+        .bus = I2C_BUS,
+    };
+    bh1750_configure(&dev, BH1750_CONTINUOUS_MODE | BH1750_HIGH_RES_MODE);
+
+    while (1) {
+        while(1) {
+            vTaskDelay(200 / portTICK_PERIOD_MS);
+            printf("Lux: %d\n", bh1750_read(&dev));
+        }
+    }
+}
+
+void user_init(void)
+{
+    uart_set_baud(0, 115200);
+
+    // Just some information
+    printf("\n");
+    printf("SDK version : %s\n", sdk_system_get_sdk_version());
+    printf("GIT version : %s\n", GITSHORTREV);
+
+    i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
+
+    xTaskCreate(measure, "measure_task", 256, NULL, 2, NULL);
+}
diff --git a/examples/blink_timers/blink_timers.c b/examples/blink_timers/blink_timers.c
index 177cff3..bef887d 100644
--- a/examples/blink_timers/blink_timers.c
+++ b/examples/blink_timers/blink_timers.c
@@ -17,13 +17,13 @@ const int freq_frc2 = 10;
 static volatile uint32_t frc1_count;
 static volatile uint32_t frc2_count;
 
-void frc1_interrupt_handler(void)
+void frc1_interrupt_handler(void *arg)
 {
     frc1_count++;
     gpio_toggle(gpio_frc1);
 }
 
-void frc2_interrupt_handler(void)
+void frc2_interrupt_handler(void *arg)
 {
     /* FRC2 needs the match register updated on each timer interrupt */
     timer_set_frequency(FRC2, freq_frc2);
@@ -47,8 +47,8 @@ void user_init(void)
     timer_set_run(FRC2, false);
 
     /* set up ISRs */
-    _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler);
-    _xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler);
+    _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL);
+    _xt_isr_attach(INUM_TIMER_FRC2, frc2_interrupt_handler, NULL);
 
     /* configure timer frequencies */
     timer_set_frequency(FRC1, freq_frc1);
diff --git a/examples/bmp180_i2c/bmp180_i2c.c b/examples/bmp180_i2c/bmp180_i2c.c
index 1e188bc..7153c64 100644
--- a/examples/bmp180_i2c/bmp180_i2c.c
+++ b/examples/bmp180_i2c/bmp180_i2c.c
@@ -13,18 +13,25 @@
 // BMP180 driver
 #include "bmp180/bmp180.h"
 
-#define MY_EVT_TIMER  0x01
-#define MY_EVT_BMP180 0x02
-
+#define I2C_BUS 0
 #define SCL_PIN GPIO_ID_PIN((0))
 #define SDA_PIN GPIO_ID_PIN((2))
 
+#define MY_EVT_TIMER  0x01
+#define MY_EVT_BMP180 0x02
+
 typedef struct
 {
     uint8_t event_type;
     bmp180_result_t bmp180_data;
 } my_event_t;
 
+//device descriptor
+i2c_dev_t dev = {
+    .addr = BMP180_DEVICE_ADDRESS,
+    .bus = I2C_BUS,
+};
+
 // Communication Queue
 static QueueHandle_t mainqueue;
 static TimerHandle_t timerHandle;
@@ -70,7 +77,7 @@ void bmp180_task(void *pvParameters)
         case MY_EVT_TIMER:
             printf("%s: Received Timer Event\n", __FUNCTION__);
 
-            bmp180_trigger_measurement(com_queue);
+            bmp180_trigger_measurement(&dev, com_queue);
             break;
         case MY_EVT_BMP180:
             printf("%s: Received BMP180 Event temp:=%d.%dC press=%d.%02dhPa\n", __FUNCTION__, \
@@ -91,6 +98,9 @@ void user_setup(void)
 
     // Give the UART some time to settle
     sdk_os_delay_us(500);
+
+    // Init I2C bus Interface
+    i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
 }
 
 void user_init(void)
@@ -107,7 +117,7 @@ void user_init(void)
     bmp180_informUser = bmp180_i2c_informUser;
 
     // Init BMP180 Interface
-    bmp180_init(SCL_PIN, SDA_PIN);
+    bmp180_init(&dev);
 
     // Create Main Communication Queue
     mainqueue = xQueueCreate(10, sizeof(my_event_t));
diff --git a/examples/bmp280/bmp280_example.c b/examples/bmp280/bmp280_example.c
index c4c7c11..4ef7ec2 100644
--- a/examples/bmp280/bmp280_example.c
+++ b/examples/bmp280/bmp280_example.c
@@ -10,9 +10,9 @@
 #include "bmp280/bmp280.h"
 
 // In forced mode user initiate measurement each time.
-// In normal mode measurement is done continuously with specified standby time. 
+// In normal mode measurement is done continuously with specified standby time.
 // #define MODE_FORCED
-
+const uint8_t i2c_bus = 0;
 const uint8_t scl_pin = 0;
 const uint8_t sda_pin = 2;
 
@@ -26,7 +26,8 @@ static void bmp280_task_forced(void *pvParameters)
     params.mode = BMP280_MODE_FORCED;
 
     bmp280_t bmp280_dev;
-    bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0;
+    bmp280_dev.i2c_dev.bus = i2c_bus;
+    bmp280_dev.i2c_dev.addr = BMP280_I2C_ADDRESS_0;
 
     while (1) {
         while (!bmp280_init(&bmp280_dev, ¶ms)) {
@@ -67,7 +68,8 @@ static void bmp280_task_normal(void *pvParameters)
     bmp280_init_default_params(¶ms);
 
     bmp280_t bmp280_dev;
-    bmp280_dev.i2c_addr = BMP280_I2C_ADDRESS_0;
+    bmp280_dev.i2c_dev.bus = i2c_bus;
+    bmp280_dev.i2c_dev.addr = BMP280_I2C_ADDRESS_0;
 
     while (1) {
         while (!bmp280_init(&bmp280_dev, ¶ms)) {
@@ -103,7 +105,7 @@ void user_init(void)
     printf("SDK version : %s\n", sdk_system_get_sdk_version());
     printf("GIT version : %s\n", GITSHORTREV);
 
-    i2c_init(scl_pin, sda_pin);
+    i2c_init(i2c_bus, scl_pin, sda_pin, I2C_FREQ_400K);
 
 #ifdef MODE_FORCED
     xTaskCreate(bmp280_task_forced, "bmp280_task", 256, NULL, 2, NULL);
diff --git a/examples/ds1307/main.c b/examples/ds1307/main.c
index a1b847e..a276f0b 100644
--- a/examples/ds1307/main.c
+++ b/examples/ds1307/main.c
@@ -11,6 +11,7 @@
 #include 
 #include 
 
+#define I2C_BUS 0
 #define SCL_PIN 5
 #define SDA_PIN 4
 
@@ -19,8 +20,12 @@ void user_init(void)
     uart_set_baud(0, 115200);
     printf("SDK version:%s\n", sdk_system_get_sdk_version());
 
-    i2c_init(SCL_PIN, SDA_PIN);
-    ds1307_start(true);
+    i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K);
+    i2c_dev_t dev = {
+        .addr = DS1307_ADDR,
+        .bus = I2C_BUS,
+    };
+    ds1307_start(&dev, true);
 
     // setup datetime: 2016-10-09 13:50:10
     struct tm time = {
@@ -31,11 +36,11 @@ void user_init(void)
         .tm_min  = 50,
         .tm_sec  = 10
     };
-    ds1307_set_time(&time);
+    ds1307_set_time(&dev, &time);
 
     while (true)
     {
-        ds1307_get_time(&time);
+        ds1307_get_time(&dev, &time);
 
         printf("%04d-%02d-%02d %02d:%02d:%02d\n", time.tm_year, time.tm_mon + 1,
             time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec);
diff --git a/examples/ds3231_test/ds3231_test.c b/examples/ds3231_test/ds3231_test.c
index 858b0a0..b6f41bb 100644
--- a/examples/ds3231_test/ds3231_test.c
+++ b/examples/ds3231_test/ds3231_test.c
@@ -1,4 +1,4 @@
-/* Test code for DS3231 high precision RTC module 
+/* Test code for DS3231 high precision RTC module
  *
  * Part of esp-open-rtos
  * Copyright (C) 2016 Bhuvanchandra DV 
@@ -12,15 +12,21 @@
 
 #include "ds3231/ds3231.h"
 
+#define ADDR DS3231_ADDR
+#define I2C_BUS 0
+
 void task1(void *pvParameters)
 {
     struct tm time;
     float tempFloat;
-
+    i2c_dev_t dev = {
+        .addr = ADDR,
+        .bus = I2C_BUS,
+    };
     while(1) {
         vTaskDelay(100);
-        ds3231_getTime(&time);
-	ds3231_getTempFloat(&tempFloat);
+        ds3231_getTime(&dev, &time);
+	    ds3231_getTempFloat(&dev, &tempFloat);
         printf("TIME:%d:%d:%d, TEMPERATURE:%.2f DegC\r\n", time.tm_hour, time.tm_min, time.tm_sec, tempFloat);
     }
 }
@@ -35,7 +41,7 @@ void user_init(void)
     printf("SDK version : %s\n", sdk_system_get_sdk_version());
     printf("GIT version : %s\n", GITSHORTREV);
 
-    ds3231_Init(scl, sda);
+    i2c_init(0,scl,sda,I2C_FREQ_400K);
 
     xTaskCreate(task1, "tsk1", 256, NULL, 2, NULL);
 }
diff --git a/examples/experiments/timers/timers.c b/examples/experiments/timers/timers.c
index a2e5e66..c889643 100644
--- a/examples/experiments/timers/timers.c
+++ b/examples/experiments/timers/timers.c
@@ -97,7 +97,7 @@ void timerRegTask(void *pvParameters)
     }
 }
 
-IRAM void frc1_handler(void)
+IRAM void frc1_handler(void *arg)
 {
     frc1_handler_call_count++;
     frc1_last_count_val = TIMER(0).COUNT;
@@ -106,7 +106,7 @@ IRAM void frc1_handler(void)
     //TIMER_FRC1_MATCH_REG = frc1_last_count_val + 0x100000;
 }
 
-void frc2_handler(void)
+void frc2_handler(void *arg)
 {
     frc2_handler_call_count++;
     frc2_last_count_val = TIMER(1).COUNT;
@@ -127,9 +127,9 @@ void user_init(void)
     TIMER(1).LOAD = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_256);
 
     DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER0 | DPORT_INT_ENABLE_TIMER1;
-    _xt_isr_attach(INUM_TIMER_FRC1, frc1_handler);
+    _xt_isr_attach(INUM_TIMER_FRC1, frc1_handler, NULL);
     _xt_isr_unmask(1<
 #include 
 
+#define I2C_BUS 0
 #define SCL_PIN 5
 #define SDA_PIN 4
 
@@ -19,20 +20,24 @@ void user_init(void)
     uart_set_baud(0, 115200);
     printf("SDK version:%s\n\n", sdk_system_get_sdk_version());
 
-    i2c_init(SCL_PIN, SDA_PIN);
+    i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K);
+    i2c_dev_t dev = {
+        .addr = HMC5883L_ADDR,
+        .bus = I2C_BUS,
+    };
 
-    while (!hmc5883l_init())
+    while (!hmc5883l_init(&dev))
         printf("Device not found\n");
 
-    hmc5883l_set_operating_mode(HMC5883L_MODE_CONTINUOUS);
-    hmc5883l_set_samples_averaged(HMC5883L_SAMPLES_8);
-    hmc5883l_set_data_rate(HMC5883L_DATA_RATE_07_50);
-    hmc5883l_set_gain(HMC5883L_GAIN_1090);
+    hmc5883l_set_operating_mode(&dev, HMC5883L_MODE_CONTINUOUS);
+    hmc5883l_set_samples_averaged(&dev, HMC5883L_SAMPLES_8);
+    hmc5883l_set_data_rate(&dev, HMC5883L_DATA_RATE_07_50);
+    hmc5883l_set_gain(&dev, HMC5883L_GAIN_1090);
 
     while (true)
     {
         hmc5883l_data_t data;
-        hmc5883l_get_data(&data);
+        hmc5883l_get_data(&dev, &data);
         printf("Magnetic data: X:%.2f mG, Y:%.2f mG, Z:%.2f mG\n", data.x, data.y, data.z);
 
         for (uint32_t i = 0; i < 1000; i++)
diff --git a/examples/http_get/http_get.c b/examples/http_get/http_get.c
index 0fe0ae1..766dd81 100644
--- a/examples/http_get/http_get.c
+++ b/examples/http_get/http_get.c
@@ -20,9 +20,9 @@
 
 #include "ssid_config.h"
 
-#define WEB_SERVER "chainxor.org"
+#define WEB_SERVER "ipv6.google.com"
 #define WEB_PORT 80
-#define WEB_URL "http://chainxor.org/"
+#define WEB_PATH "/"
 
 void http_get_task(void *pvParameters)
 {
@@ -31,7 +31,7 @@ void http_get_task(void *pvParameters)
 
     while(1) {
         const struct addrinfo hints = {
-            .ai_family = AF_INET,
+            .ai_family = AF_UNSPEC,
             .ai_socktype = SOCK_STREAM,
         };
         struct addrinfo *res;
@@ -39,7 +39,7 @@ void http_get_task(void *pvParameters)
         printf("Running DNS lookup for %s...\r\n", WEB_SERVER);
         int err = getaddrinfo(WEB_SERVER, "80", &hints, &res);
 
-        if(err != 0 || res == NULL) {
+        if (err != 0 || res == NULL) {
             printf("DNS lookup failed err=%d res=%p\r\n", err, res);
             if(res)
                 freeaddrinfo(res);
@@ -47,9 +47,28 @@ void http_get_task(void *pvParameters)
             failures++;
             continue;
         }
-        /* Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
-        struct in_addr *addr = &((struct sockaddr_in *)res->ai_addr)->sin_addr;
-        printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(*addr));
+
+#if LWIP_IPV6
+        {
+            struct netif *netif = sdk_system_get_netif(0);
+            int i;
+            for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
+                printf("  ip6 %d state %x\n", i, netif_ip6_addr_state(netif, i));
+                if (!ip6_addr_isinvalid(netif_ip6_addr_state(netif, i)))
+                    printf("  ip6 addr %d = %s\n", i, ip6addr_ntoa(netif_ip6_addr(netif, i)));
+            }
+        }
+#endif
+
+        struct sockaddr *sa = res->ai_addr;
+        if (sa->sa_family == AF_INET) {
+            printf("DNS lookup succeeded. IP=%s\r\n", inet_ntoa(((struct sockaddr_in *)sa)->sin_addr));
+        }
+#if LWIP_IPV6
+        if (sa->sa_family == AF_INET6) {
+            printf("DNS lookup succeeded. IP=%s\r\n", inet6_ntoa(((struct sockaddr_in6 *)sa)->sin6_addr));
+        }
+#endif
 
         int s = socket(res->ai_family, res->ai_socktype, 0);
         if(s < 0) {
@@ -75,8 +94,10 @@ void http_get_task(void *pvParameters)
         freeaddrinfo(res);
 
         const char *req =
-            "GET "WEB_URL"\r\n"
+            "GET "WEB_PATH" HTTP/1.1\r\n"
+            "Host: "WEB_SERVER"\r\n"
             "User-Agent: esp-open-rtos/0.1 esp8266\r\n"
+            "Connection: close\r\n"
             "\r\n";
         if (write(s, req, strlen(req)) < 0) {
             printf("... socket send failed\r\n");
@@ -126,6 +147,6 @@ void user_init(void)
     sdk_wifi_set_opmode(STATION_MODE);
     sdk_wifi_station_set_config(&config);
 
-    xTaskCreate(&http_get_task, "get_task", 256, NULL, 2, NULL);
+    xTaskCreate(&http_get_task, "get_task", 384, NULL, 2, NULL);
 }
 
diff --git a/examples/http_get_mbedtls/http_get_mbedtls.c b/examples/http_get_mbedtls/http_get_mbedtls.c
index 596a1f7..0200a66 100644
--- a/examples/http_get_mbedtls/http_get_mbedtls.c
+++ b/examples/http_get_mbedtls/http_get_mbedtls.c
@@ -33,7 +33,7 @@
    errors at link time if functions don't exist.) */
 #include "mbedtls/config.h"
 
-#include "mbedtls/net.h"
+#include "mbedtls/net_sockets.h"
 #include "mbedtls/debug.h"
 #include "mbedtls/ssl.h"
 #include "mbedtls/entropy.h"
diff --git a/examples/http_server/fsdata/fs/about.html b/examples/http_server/fsdata/fs/about.html
index 46eb050..18aad61 100644
--- a/examples/http_server/fsdata/fs/about.html
+++ b/examples/http_server/fsdata/fs/about.html
@@ -19,7 +19,7 @@
 			

About

This server is based on httpd from LwIP.

To enable debugging compile with flags -DLWIP_DEBUG=1 -DHTTPD_DEBUG=LWIP_DBG_ON.

-

For more info see HTTP Server documentation.

+

For more info see HTTP Server documentation.

diff --git a/examples/i2c_lcd_test/main.c b/examples/i2c_lcd_test/main.c index 1951777..cb2af04 100644 --- a/examples/i2c_lcd_test/main.c +++ b/examples/i2c_lcd_test/main.c @@ -13,6 +13,7 @@ #include +#define I2C_BUS 0 #define SCL_PIN 5 #define SDA_PIN 4 #define ADDR 0x27 @@ -27,10 +28,11 @@ void user_init(void) uart_set_baud(0, 115200); printf("SDK version:%s\n", sdk_system_get_sdk_version()); - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); hd44780_t lcd = { - .addr = ADDR, + .i2c_dev.bus = I2C_BUS, + .i2c_dev.addr = ADDR, .font = HD44780_FONT_5X8, .lines = 2, .pins = { diff --git a/examples/i2s_audio/i2s_audio_example.c b/examples/i2s_audio/i2s_audio_example.c index 1972692..7b48c02 100644 --- a/examples/i2s_audio/i2s_audio_example.c +++ b/examples/i2s_audio/i2s_audio_example.c @@ -88,7 +88,7 @@ static inline void init_descriptors_list() } // DMA interrupt handler. It is called each time a DMA block is finished processing. -static void dma_isr_handler(void) +static void dma_isr_handler(void *args) { portBASE_TYPE task_awoken = pdFALSE; @@ -168,7 +168,7 @@ void play_task(void *pvParameters) i2s_pins_t i2s_pins = {.data = true, .clock = true, .ws = true}; - i2s_dma_init(dma_isr_handler, clock_div, i2s_pins); + i2s_dma_init(dma_isr_handler, NULL, clock_div, i2s_pins); while (1) { init_descriptors_list(); diff --git a/examples/ina3221_test/main.c b/examples/ina3221_test/main.c index 5a883d2..cd8150e 100644 --- a/examples/ina3221_test/main.c +++ b/examples/ina3221_test/main.c @@ -13,6 +13,7 @@ #include #include "ina3221/ina3221.h" +#define I2C_BUS 0 #define PIN_SCL 5 #define PIN_SDA 2 #define ADDR INA3221_ADDR_0 @@ -33,7 +34,8 @@ void ina_measure(void *pvParameters) // Create ina3221 device ina3221_t dev = { - .addr = ADDR, + .i2c_dev.bus = I2C_BUS, + .i2c_dev.addr = ADDR, .shunt = { 100 ,100 ,100 }, // shunt values are 100 mOhm for each channel .mask.mask_register = INA3221_DEFAULT_MASK, // Init .config.config_register = INA3221_DEFAULT_CONFIG, // Init @@ -120,7 +122,7 @@ void user_init(void) uart_set_baud(0, 115200); printf("SDK version:%s\n", sdk_system_get_sdk_version()); - i2c_init(PIN_SCL,PIN_SDA); + i2c_init(I2C_BUS, PIN_SCL, PIN_SDA, I2C_FREQ_400K); xTaskCreate(ina_measure, "Measurements_task", 512, NULL, 2, NULL); } diff --git a/examples/mcp4725_test/main.c b/examples/mcp4725_test/main.c index f3eae0b..b7d42af 100644 --- a/examples/mcp4725_test/main.c +++ b/examples/mcp4725_test/main.c @@ -14,14 +14,15 @@ #include #include +#define I2C_BUS 0 #define SCL_PIN 5 #define SDA_PIN 4 #define ADDR MCP4725A0_ADDR0 #define VDD 3.3 -inline static void wait_for_eeprom() +inline static void wait_for_eeprom(i2c_dev_t* dev) { - while (mcp4725_eeprom_busy(ADDR)) + while (mcp4725_eeprom_busy(dev)) { printf("...DAC is busy, waiting...\n"); vTaskDelay(1); @@ -33,21 +34,25 @@ void user_init(void) uart_set_baud(0, 115200); printf("SDK version:%s\n", sdk_system_get_sdk_version()); - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); + i2c_dev_t dev = { + .addr = ADDR, + .bus = I2C_BUS, + }; // setup EEPROM values - if (mcp4725_get_power_mode(ADDR, true) != MCP4725_PM_NORMAL) + if (mcp4725_get_power_mode(&dev, true) != MCP4725_PM_NORMAL) { printf("DAC was sleeping... Wake up Neo!\n"); - mcp4725_set_power_mode(ADDR, MCP4725_PM_NORMAL, true); - wait_for_eeprom(); + mcp4725_set_power_mode(&dev, MCP4725_PM_NORMAL, true); + wait_for_eeprom(&dev); } printf("Set default DAC ouptut value to MAX...\n"); - mcp4725_set_raw_output(ADDR, MCP4725_MAX_VALUE, true); - wait_for_eeprom(); + mcp4725_set_raw_output(&dev, MCP4725_MAX_VALUE, true); + wait_for_eeprom(&dev); - printf("And now default DAC output value is 0x%03x\n", mcp4725_get_raw_output(ADDR, true)); + printf("And now default DAC output value is 0x%03x\n", mcp4725_get_raw_output(&dev, true)); printf("Now let's generate the sawtooth wave in slow manner\n"); @@ -58,7 +63,7 @@ void user_init(void) if (vout > VDD) vout = 0; printf("Vout: %.02f\n", vout); - mcp4725_set_voltage(ADDR, VDD, vout, false); + mcp4725_set_voltage(&dev, VDD, vout, false); // It will be very low freq wave vTaskDelay(100 / portTICK_PERIOD_MS); diff --git a/examples/ms561101ba03/main.c b/examples/ms561101ba03/main.c index 9e993d1..b4b9c73 100644 --- a/examples/ms561101ba03/main.c +++ b/examples/ms561101ba03/main.c @@ -13,18 +13,20 @@ #include #include +#define I2C_BUS 0 #define SCL_PIN 5 #define SDA_PIN 4 void user_init(void) { - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); uart_set_baud(0, 115200); printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); ms561101ba03_t device = { - .addr = MS561101BA03_ADDR_CSB_LOW, + .i2c_dev.bus = I2C_BUS, + .i2c_dev.addr = MS561101BA03_ADDR_CSB_LOW, .osr = MS561101BA03_OSR_4096, }; diff --git a/examples/pca9685_pwm/main.c b/examples/pca9685_pwm/main.c index b191334..07c0aac 100644 --- a/examples/pca9685_pwm/main.c +++ b/examples/pca9685_pwm/main.c @@ -11,8 +11,9 @@ #include #include -#define ADDR 0x40 +#define ADDR PCA9685_ADDR_BASE +#define I2C_BUS 0 #define SCL_PIN 5 #define SDA_PIN 4 @@ -23,19 +24,23 @@ void user_init(void) uart_set_baud(0, 115200); printf("SDK version:%s\n", sdk_system_get_sdk_version()); - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); + i2c_dev_t dev = { + .addr = ADDR, + .bus = I2C_BUS, + }; - pca9685_init(ADDR); + pca9685_init(&dev); - pca9685_set_pwm_frequency(ADDR, 1000); - printf("Freq 1000Hz, real %d\n", pca9685_get_pwm_frequency(ADDR)); + pca9685_set_pwm_frequency(&dev, 1000); + printf("Freq 1000Hz, real %d\n", pca9685_get_pwm_frequency(&dev)); uint16_t val = 0; while (true) { printf("Set ch0 to %d, ch4 to %d\n", val, 4096 - val); - pca9685_set_pwm_value(ADDR, 0, val); - pca9685_set_pwm_value(ADDR, 4, 4096 - val); + pca9685_set_pwm_value(&dev, 0, val); + pca9685_set_pwm_value(&dev, 4, 4096 - val); if (val++ == 4096) val = 0; diff --git a/examples/pcf8591/Makefile b/examples/pcf8591/Makefile new file mode 100644 index 0000000..f9d5768 --- /dev/null +++ b/examples/pcf8591/Makefile @@ -0,0 +1,3 @@ +PROGRAM = pcf8591 +EXTRA_COMPONENTS = extras/i2c extras/pcf8591 +include ../../common.mk diff --git a/examples/pcf8591/main.c b/examples/pcf8591/main.c new file mode 100644 index 0000000..a4dc8a3 --- /dev/null +++ b/examples/pcf8591/main.c @@ -0,0 +1,42 @@ +#include + +#include "espressif/esp_common.h" +#include "esp/uart.h" + +#include "FreeRTOS.h" +#include "task.h" + +#include "i2c/i2c.h" +#include "pcf8591/pcf8591.h" + +#define ADDR PCF8591_DEFAULT_ADDRESS +#define I2C_BUS 0 +#define SCL_PIN 5 +#define SDA_PIN 4 + +static void measure(void *pvParameters) +{ + i2c_dev_t dev = { + .addr = ADDR, + .bus = I2C_BUS, + }; + while (1) + { + vTaskDelay(1000 / portTICK_PERIOD_MS); + printf("Value: %d\n", pcf8591_read(&dev, 0x03)); + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + + // Just some information + printf("\n"); + printf("SDK version : %s\n", sdk_system_get_sdk_version()); + printf("GIT version : %s\n", GITSHORTREV); + + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); + + xTaskCreate(measure, "measure_task", 256, NULL, 2, NULL); +} diff --git a/examples/softuart/LICENSE b/examples/softuart/LICENSE new file mode 100644 index 0000000..104c838 --- /dev/null +++ b/examples/softuart/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (C) 2016 Bernhard Guillon +Copyright (c) 2015 plieningerweb + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/examples/softuart/Makefile b/examples/softuart/Makefile new file mode 100644 index 0000000..5b3f951 --- /dev/null +++ b/examples/softuart/Makefile @@ -0,0 +1,4 @@ +PROGRAM = softuart +EXTRA_COMPONENTS = extras/softuart +ESPBAUD = 460800 +include ../../common.mk diff --git a/examples/softuart/main.c b/examples/softuart/main.c new file mode 100644 index 0000000..75b280e --- /dev/null +++ b/examples/softuart/main.c @@ -0,0 +1,40 @@ +/* + * Softuart example + * + * Copyright (C) 2017 Ruslan V. Uss + * Copyright (C) 2016 Bernhard Guillon + * Copyright (c) 2015 plieningerweb + * + * MIT Licensed as described in the file LICENSE + */ +#include +#include +#include +#include +//#include +//#include + +#include + +#define RX_PIN 5 +#define TX_PIN 4 + +void user_init(void) +{ + // setup real UART for now + uart_set_baud(0, 115200); + printf("SDK version:%s\n\n", sdk_system_get_sdk_version()); + + // setup software uart to 9600 8n1 + softuart_open(0, 9600, RX_PIN, TX_PIN); + + while (true) + { + if (!softuart_available(0)) + continue; + + char c = softuart_read(0); + printf("input: %c, 0x%02x\n", c, c); + softuart_puts(0, "start\r\n"); + } +} diff --git a/examples/ssd1306_example/main.c b/examples/ssd1306_example/main.c index 58781c5..f88d798 100644 --- a/examples/ssd1306_example/main.c +++ b/examples/ssd1306_example/main.c @@ -23,6 +23,7 @@ #ifdef I2C_CONNECTION #define PROTOCOL SSD1306_PROTO_I2C #define ADDR SSD1306_I2C_ADDR_0 + #define I2C_BUS 0 #define SCL_PIN 5 #define SDA_PIN 4 #else @@ -35,7 +36,8 @@ static const ssd1306_t dev = { .protocol = PROTOCOL, #ifdef I2C_CONNECTION - .addr = ADDR, + .i2c_dev.bus = I2C_BUS, + .i2c_dev.addr = ADDR, #else .cs_pin = CS_PIN, .dc_pin = DC_PIN, @@ -97,7 +99,7 @@ void user_init(void) printf("SDK version:%s\n", sdk_system_get_sdk_version()); #ifdef I2C_CONNECTION - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K); #endif while (ssd1306_init(&dev) != 0) diff --git a/examples/ssd1306_fps/main.c b/examples/ssd1306_fps/main.c index b35dbfb..dc1f1a9 100644 --- a/examples/ssd1306_fps/main.c +++ b/examples/ssd1306_fps/main.c @@ -29,6 +29,7 @@ #ifdef I2C_CONNECTION #define PROTOCOL SSD1306_PROTO_I2C #define ADDR SSD1306_I2C_ADDR_0 + #define I2C_BUS 0 #define SCL_PIN 5 #define SDA_PIN 4 #else @@ -43,7 +44,8 @@ static const ssd1306_t dev = { .protocol = PROTOCOL, #ifdef I2C_CONNECTION - .addr = ADDR, +.i2c_dev.bus = I2C_BUS, +.i2c_dev.addr = ADDR, #else .cs_pin = CS_PIN, .dc_pin = DC_PIN, @@ -162,7 +164,7 @@ void user_init(void) printf("SDK version:%s\n", sdk_system_get_sdk_version()); #ifdef I2C_CONNECTION - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_400K); #endif while (ssd1306_init(&dev) != 0) { diff --git a/examples/sysparam_editor/Makefile b/examples/sysparam_editor/Makefile index a774b68..f63e4e5 100644 --- a/examples/sysparam_editor/Makefile +++ b/examples/sysparam_editor/Makefile @@ -8,7 +8,7 @@ include ../../common.mk # `make dump-flash` can be used to view the current contents of the sysparam # regions in flash. dump-flash: - esptool.py read_flash 0x1f8000 8192 r1.bin + esptool.py read_flash 0x1f7000 8192 r1.bin hexdump -C r1.bin - esptool.py read_flash 0x1fa000 8192 r2.bin + esptool.py read_flash 0x1f9000 8192 r2.bin hexdump -C r2.bin diff --git a/examples/sysparam_editor/sysparam_editor.c b/examples/sysparam_editor/sysparam_editor.c index 0b58efd..29bf78e 100644 --- a/examples/sysparam_editor/sysparam_editor.c +++ b/examples/sysparam_editor/sysparam_editor.c @@ -45,7 +45,7 @@ size_t tty_readline(char *buffer, size_t buf_size, bool echo) { while (true) { c = getchar(); - if (c == '\r') { + if (c == '\r' || c == '\n') { if (echo) putchar('\n'); break; } else if (c == '\b' || c == 0x7f) { @@ -173,7 +173,7 @@ void sysparam_editor_task(void *pvParameters) { // stuff, so if the user uses this utility to reformat it, it will put // it somewhere the system will find it later num_sectors = DEFAULT_SYSPARAM_SECTORS; - base_addr = sdk_flashchip.chip_size - (4 + num_sectors) * sdk_flashchip.sector_size; + base_addr = sdk_flashchip.chip_size - (5 + num_sectors) * sdk_flashchip.sector_size; } while (true) { printf("==> "); @@ -246,5 +246,7 @@ void user_init(void) { uart_set_baud(0, 115200); + sdk_wifi_set_opmode(NULL_MODE); + xTaskCreate(sysparam_editor_task, "sysparam_editor_task", 512, NULL, 2, NULL); } diff --git a/examples/tick_idle_hooks/FreeRTOSConfig.h b/examples/tick_idle_hooks/FreeRTOSConfig.h new file mode 100644 index 0000000..e21d827 --- /dev/null +++ b/examples/tick_idle_hooks/FreeRTOSConfig.h @@ -0,0 +1,10 @@ +/** + + Configuration overrides for FreeRTOS. + +**/ + +#define configUSE_IDLE_HOOK 1 +#define configUSE_TICK_HOOK 1 + +#include_next "FreeRTOSConfig.h" \ No newline at end of file diff --git a/examples/tick_idle_hooks/Makefile b/examples/tick_idle_hooks/Makefile new file mode 100644 index 0000000..717b163 --- /dev/null +++ b/examples/tick_idle_hooks/Makefile @@ -0,0 +1,3 @@ +# Simple makefile for simple example +PROGRAM=simple +include ../../common.mk diff --git a/examples/tick_idle_hooks/hooks_example.c b/examples/tick_idle_hooks/hooks_example.c new file mode 100644 index 0000000..8b9fa49 --- /dev/null +++ b/examples/tick_idle_hooks/hooks_example.c @@ -0,0 +1,56 @@ +/* Very basic example that just demonstrates we can run at all! + */ +#include "espressif/esp_common.h" +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +void vApplicationIdleHook(void) +{ + // Go to sleep; either deeply (waiting for an event to wake) + // or light, allowing FreeRTOS ticks to wake + sdk_wifi_set_sleep_type(WIFI_SLEEP_MODEM); +} + +void vApplicationTickHook(void) +{ + // Called every tick +} + +void task1(void *pvParameters) +{ + QueueHandle_t *queue = (QueueHandle_t *)pvParameters; + printf("Hello from task1!\r\n"); + uint32_t count = 0; + while(1) { + vTaskDelay(100); + xQueueSend(*queue, &count, 0); + count++; + } +} + +void task2(void *pvParameters) +{ + printf("Hello from task 2!\r\n"); + QueueHandle_t *queue = (QueueHandle_t *)pvParameters; + while(1) { + uint32_t count; + if(xQueueReceive(*queue, &count, 1000)) { + printf("Got %u\n", count); + } else { + printf("No msg :(\n"); + } + } +} + +static QueueHandle_t mainqueue; + +void user_init(void) +{ + uart_set_baud(0, 115200); + printf("SDK version:%s\n", sdk_system_get_sdk_version()); + mainqueue = xQueueCreate(10, sizeof(uint32_t)); + xTaskCreate(task1, "tsk1", 256, &mainqueue, 2, NULL); + xTaskCreate(task2, "tsk2", 256, &mainqueue, 2, NULL); +} diff --git a/examples/tls_server/tls_server.c b/examples/tls_server/tls_server.c index 7959609..8ecfa56 100644 --- a/examples/tls_server/tls_server.c +++ b/examples/tls_server/tls_server.c @@ -43,7 +43,7 @@ extern const char *server_key; errors at link time if functions don't exist.) */ #include "mbedtls/config.h" -#include "mbedtls/net.h" +#include "mbedtls/net_sockets.h" #include "mbedtls/debug.h" #include "mbedtls/ssl.h" #include "mbedtls/entropy.h" @@ -202,9 +202,8 @@ void tls_server_task(void *pvParameters) socklen_t peer_addr_len = sizeof(struct sockaddr_in); getpeername(client_ctx.fd, (struct sockaddr *)&peer_addr, &peer_addr_len); unsigned char buf[256]; - int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\nFree heap size is %d bytes\n", - ip4_addr1(&peer_addr.sin_addr), ip4_addr2(&peer_addr.sin_addr), - ip4_addr3(&peer_addr.sin_addr), ip4_addr4(&peer_addr.sin_addr), + int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\nFree heap size is %d bytes\n", + IP2STR((ip4_addr_t *)&peer_addr.sin_addr.s_addr), peer_addr.sin_port, xPortGetFreeHeapSize()); while((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { @@ -216,6 +215,7 @@ void tls_server_task(void *pvParameters) } len = ret; + ret = 0; printf(" %d bytes written. Closing socket on client.\n\n%s", len, (char *) buf); mbedtls_ssl_close_notify(&ssl); diff --git a/examples/tls_server_bearssl/tls_server_bearssl.c b/examples/tls_server_bearssl/tls_server_bearssl.c index 09632ae..b1e48dc 100644 --- a/examples/tls_server_bearssl/tls_server_bearssl.c +++ b/examples/tls_server_bearssl/tls_server_bearssl.c @@ -146,9 +146,8 @@ void tls_server_task(void *pvParameters) /* Prepare a message to the client */ unsigned char buf[100]; - int len = sprintf((char *) buf, "O hai, client %d.%d.%d.%d:%d\r\nFree heap size is %d bytes\r\n", - ip4_addr1(&sa.sin_addr), ip4_addr2(&sa.sin_addr), - ip4_addr3(&sa.sin_addr), ip4_addr4(&sa.sin_addr), + int len = sprintf((char *) buf, "O hai, client " IPSTR ":%d\r\nFree heap size is %d bytes\r\n", + IP2STR((ip4_addr_t *)&sa.sin_addr.s_addr), ntohs(sa.sin_port), xPortGetFreeHeapSize()); /* Send the message and close the connection */ diff --git a/examples/tsl2561/tsl2561_example.c b/examples/tsl2561/tsl2561_example.c index b97804b..6f3582f 100644 --- a/examples/tsl2561/tsl2561_example.c +++ b/examples/tsl2561/tsl2561_example.c @@ -16,6 +16,7 @@ * Connect 3.3v from the ESP to Vin and GND to GND */ +#define I2C_BUS (0) #define SCL_PIN (2) #define SDA_PIN (0) @@ -27,7 +28,8 @@ void tsl2561MeasurementTask(void *pvParameters) // TSL2561_I2C_ADDR_VCC (0x49) // TSL2561_I2C_ADDR_GND (0x29) // TSL2561_I2C_ADDR_FLOAT (0x39) Default - lightSensor.i2c_addr = TSL2561_I2C_ADDR_FLOAT; + lightSensor.i2c_dev.bus = I2C_BUS; + lightSensor.i2c_dev.addr = TSL2561_I2C_ADDR_FLOAT; tsl2561_init(&lightSensor); @@ -63,7 +65,7 @@ void tsl2561MeasurementTask(void *pvParameters) void user_init(void) { uart_set_baud(0, 115200); - i2c_init(SCL_PIN, SDA_PIN); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); xTaskCreate(tsl2561MeasurementTask, "tsl2561MeasurementTask", 256, NULL, 2, NULL); } diff --git a/examples/tsl4531/Makefile b/examples/tsl4531/Makefile new file mode 100644 index 0000000..f52d04f --- /dev/null +++ b/examples/tsl4531/Makefile @@ -0,0 +1,3 @@ +PROGRAM=tsl4531_example +EXTRA_COMPONENTS = extras/i2c extras/tsl4531 +include ../../common.mk diff --git a/examples/tsl4531/tsl4531_example.c b/examples/tsl4531/tsl4531_example.c new file mode 100644 index 0000000..f40213a --- /dev/null +++ b/examples/tsl4531/tsl4531_example.c @@ -0,0 +1,57 @@ +/* + * This sample code is in the public domain. + */ + +#include +#include +#include "esp/uart.h" +#include "FreeRTOS.h" +#include "i2c/i2c.h" +#include "task.h" +#include "tsl4531/tsl4531.h" + +/* An example using the TSL4531 light sensor + * to read and print lux values from a sensor + * attached to GPIO pin 2 (SCL) and GPIO pin 0 (SDA) + * Connect 3.3v from the ESP to Vin and GND to GND + */ + +#define I2C_BUS (0) +#define SCL_PIN (2) +#define SDA_PIN (0) + +void tsl4531MeasurementTask(void *pvParameters) +{ + tsl4531_t lightSensor; + lightSensor.i2c_dev.bus= I2C_BUS; + lightSensor.i2c_dev.addr= TSL4531_I2C_ADDR; + tsl4531_init(&lightSensor); + + tsl4531_set_integration_time(&lightSensor, TSL4531_INTEGRATION_400MS); + tsl4531_set_power_save_skip(&lightSensor, true); + + uint16_t lux = 0; + + while (1) + { + if (tsl4531_read_lux(&lightSensor, &lux)) + { + printf("Lux: %u\n", lux); + } + else + { + printf("Could not read data from TSL4531\n"); + } + + // 0.05 second delay + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + i2c_init(I2C_BUS, SCL_PIN, SDA_PIN, I2C_FREQ_100K); + + xTaskCreate(tsl4531MeasurementTask, "tsl4531MeasurementTask", 256, NULL, 2, NULL); +} diff --git a/examples/upnp/Makefile b/examples/upnp/Makefile new file mode 100644 index 0000000..8e82736 --- /dev/null +++ b/examples/upnp/Makefile @@ -0,0 +1,5 @@ +PROGRAM=upnp_test +OTA=1 +EXTRA_COMPONENTS=extras/rboot-ota + +include ../../common.mk diff --git a/examples/upnp/README.md b/examples/upnp/README.md new file mode 100644 index 0000000..d39056c --- /dev/null +++ b/examples/upnp/README.md @@ -0,0 +1,3 @@ +# upnp Example + +This is an example to generate an upnp server and emulate a WeMo switch recognizable by Amazon echo Dot. diff --git a/examples/upnp/httpd.c b/examples/upnp/httpd.c new file mode 100644 index 0000000..9db2465 --- /dev/null +++ b/examples/upnp/httpd.c @@ -0,0 +1,53 @@ +#include +#include +#include + +void httpd_task(void *pvParameters) +{ + struct netconn *client = NULL; + struct netconn *nc = netconn_new(NETCONN_TCP); + if (nc == NULL) { + printf("Failed to allocate socket\n"); + vTaskDelete(NULL); + } + netconn_bind(nc, IP_ADDR_ANY, 80); + netconn_listen(nc); + while (1) { + err_t err = netconn_accept(nc, &client); + if (err == ERR_OK) { + struct netbuf *nb; + if ((err = netconn_recv(client, &nb)) == ERR_OK) { + struct sdk_station_config config; + sdk_wifi_station_get_config(&config); + char * buf = + "\ + \ + \ + urn:Belkin:device:controllee:1\ + hello\ + Belkin International Inc.\ + Emulated Socket\ + 3.1415\ + uuid:Socket-1_0-38323636-4558-4dda-9188-cda0e6cc3dc0\ + 221517K0101769\ + 0\ + \ + \ + urn:Belkin:service:basicevent:1\ + urn:Belkin:serviceId:basicevent1\ + /upnp/control/basicevent1\ + /upnp/event/basicevent1\ + /eventservice.xml\ + \ + \ + \ + "; + netconn_write(client, buf, strlen(buf), NETCONN_COPY); + } + netbuf_delete(nb); + } + printf("Closing connection\n"); + netconn_close(client); + netconn_delete(client); + } +} \ No newline at end of file diff --git a/examples/upnp/httpd.h b/examples/upnp/httpd.h new file mode 100644 index 0000000..2dfdd1b --- /dev/null +++ b/examples/upnp/httpd.h @@ -0,0 +1,3 @@ +#include + +void httpd_task(void *pvParameters); diff --git a/examples/upnp/lwipopts.h b/examples/upnp/lwipopts.h new file mode 100644 index 0000000..56f45f2 --- /dev/null +++ b/examples/upnp/lwipopts.h @@ -0,0 +1,5 @@ + +#define LWIP_IGMP 1 + +/* Use the defaults for everything else */ +#include_next diff --git a/examples/upnp/upnp.c b/examples/upnp/upnp.c new file mode 100644 index 0000000..bb34cae --- /dev/null +++ b/examples/upnp/upnp.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include +#include "upnp.h" + +#define UPNP_MCAST_GRP ("239.255.255.250") +#define UPNP_MCAST_PORT (1900) + +static const char* get_my_ip(void) +{ + static char ip[16] = "0.0.0.0"; + ip[0] = 0; + struct ip_info ipinfo; + (void) sdk_wifi_get_ip_info(STATION_IF, &ipinfo); + snprintf(ip, sizeof(ip), IPSTR, IP2STR(&ipinfo.ip)); + return (char*) ip; +} + +/** + * @brief This function joins a multicast group with the specified ip/port + * @param group_ip the specified multicast group ip + * @param group_port the specified multicast port number + * @param recv the lwip UDP callback + * @retval udp_pcb* or NULL if joining failed + */ +static struct udp_pcb* mcast_join_group(char *group_ip, uint16_t group_port, void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)) +{ + bool status = false; + struct udp_pcb *upcb; + + printf("Joining mcast group %s:%d\n", group_ip, group_port); + do { + upcb = udp_new(); + if (!upcb) { + printf("Error, udp_new failed"); + break; + } + udp_bind(upcb, IP4_ADDR_ANY, group_port); + struct netif* netif = sdk_system_get_netif(STATION_IF); + if (!netif) { + printf("Error, netif is null"); + break; + } + if (!(netif->flags & NETIF_FLAG_IGMP)) { + netif->flags |= NETIF_FLAG_IGMP; + igmp_start(netif); + } + ip4_addr_t ipgroup; + ip4addr_aton(group_ip, &ipgroup); + err_t err = igmp_joingroup_netif(netif, &ipgroup); + if (ERR_OK != err) { + printf("Failed to join multicast group: %d", err); + break; + } + status = true; + } while(0); + + if (status) { + printf("Join successs\n"); + udp_recv(upcb, recv, upcb); + } else { + if (upcb) { + udp_remove(upcb); + } + upcb = NULL; + } + return upcb; +} + +static void send_udp(struct udp_pcb *upcb, const ip_addr_t *addr, u16_t port) +{ + struct pbuf *p; + char msg[500]; + snprintf(msg, sizeof(msg), + "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "DATE: Fri, 15 Apr 2016 04:56:29 GMT\r\n" + "EXT:\r\n" + "LOCATION: http://%s:80/setup.xml\r\n" + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "01-NLS: b9200ebb-736d-4b93-bf03-835149d13983\r\n" + "SERVER: Unspecified, UPnP/1.0, Unspecified\r\n" + "ST: urn:Belkin:device:**\r\n" + "USN: uuid:Socket-1_0-38323636-4558-4dda-9188-cda0e6cc3dc0::urn:Belkin:device:**\r\n" + "X-User-Agent: redsonic\r\n\r\n", get_my_ip()); + + p = pbuf_alloc(PBUF_TRANSPORT, strlen(msg)+1, PBUF_RAM); + + if (!p) { + printf("Failed to allocate transport buffer\n"); + } else { + memcpy(p->payload, msg, strlen(msg)+1); + err_t err = udp_sendto(upcb, p, addr, port); + if (err < 0) { + printf("Error sending message: %s (%d)\n", lwip_strerr(err), err); + } else { + printf("Sent message '%s'\n", msg); + } + pbuf_free(p); + } +} + +/** + * @brief This function is called when an UDP datagrm has been received on the port UDP_PORT. + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + * @retval None + */ +static void receive_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + if (p) { + printf("Msg received port:%d len:%d\n", port, p->len); + uint8_t *buf = (uint8_t*) p->payload; + printf("Msg received port:%d len:%d\nbuf: %s\n", port, p->len, buf); + + send_udp(upcb, addr, port); + + pbuf_free(p); + } +} + +/** + * @brief Initialize the upnp server + * @retval true if init was succcessful + */ +bool upnp_server_init(void) +{ + struct udp_pcb *upcb = mcast_join_group(UPNP_MCAST_GRP, UPNP_MCAST_PORT, receive_callback); + return (upcb != NULL); +} diff --git a/examples/upnp/upnp.h b/examples/upnp/upnp.h new file mode 100644 index 0000000..eb71f84 --- /dev/null +++ b/examples/upnp/upnp.h @@ -0,0 +1,2 @@ + +bool upnp_server_init(void); diff --git a/examples/upnp/upnp_test.c b/examples/upnp/upnp_test.c new file mode 100644 index 0000000..b3da04c --- /dev/null +++ b/examples/upnp/upnp_test.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lwipopts.h" +#include "upnp.h" +#include "httpd.h" + +/** User friendly FreeRTOS delay macro */ +#define delay_ms(ms) vTaskDelay(ms / portTICK_PERIOD_MS) + +/** Semaphore to signal wifi availability */ +static SemaphoreHandle_t wifi_alive; + +/** + * @brief This is the multicast task + * @param arg user supplied argument from xTaskCreate + * @retval None + */ +static void mcast_task(void *arg) +{ + xSemaphoreTake(wifi_alive, portMAX_DELAY); + xSemaphoreGive(wifi_alive); + + (void) upnp_server_init(); + while(1) { + delay_ms(2000); + } +} + +/** + * @brief This is the wifi connection task + * @param arg user supplied argument from xTaskCreate + * @retval None + */ +static void wifi_task(void *pvParameters) +{ + uint8_t status = 0; + uint8_t retries = 30; + struct sdk_station_config config = { + .ssid = WIFI_SSID, + .password = WIFI_PASS, + }; + + xSemaphoreTake(wifi_alive, portMAX_DELAY); + printf("WiFi: connecting to WiFi\n"); + sdk_wifi_set_opmode(STATION_MODE); + sdk_wifi_station_set_config(&config); + + while(1) { + while (status != STATION_GOT_IP && retries) { + status = sdk_wifi_station_get_connect_status(); + if(status == STATION_WRONG_PASSWORD) { + printf("WiFi: wrong password\n"); + break; + } else if(status == STATION_NO_AP_FOUND) { + printf("WiFi: AP not found\n"); + break; + } else if(status == STATION_CONNECT_FAIL) { + printf("WiFi: connection failed\n"); + break; + } + delay_ms(1000); + retries--; + } + if (status == STATION_GOT_IP) { + printf("WiFi: connected\n"); + xSemaphoreGive(wifi_alive); + taskYIELD(); + } + + while ((status = sdk_wifi_station_get_connect_status()) == STATION_GOT_IP) { + xSemaphoreGive(wifi_alive); + taskYIELD(); + } + printf("WiFi: disconnected\n"); + sdk_wifi_station_disconnect(); + delay_ms(1000); + } +} + +void user_init(void) +{ + uart_set_baud(0, 115200); + vSemaphoreCreateBinary(wifi_alive); + ota_tftp_init_server(TFTP_PORT); + xTaskCreate(&wifi_task, "wifi_task", 256, NULL, 2, NULL); + delay_ms(250); + xTaskCreate(&httpd_task, "http_server", 1024, NULL, 4, NULL); + xTaskCreate(&mcast_task, "mcast_task", 1024, NULL, 4, NULL); +} diff --git a/examples/wificfg/.gitignore b/examples/wificfg/.gitignore new file mode 100644 index 0000000..e067149 --- /dev/null +++ b/examples/wificfg/.gitignore @@ -0,0 +1 @@ +!local.mk diff --git a/examples/wificfg/FreeRTOSConfig.h b/examples/wificfg/FreeRTOSConfig.h new file mode 100644 index 0000000..baf25a4 --- /dev/null +++ b/examples/wificfg/FreeRTOSConfig.h @@ -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 diff --git a/examples/wificfg/Makefile b/examples/wificfg/Makefile new file mode 100644 index 0000000..2cbb996 --- /dev/null +++ b/examples/wificfg/Makefile @@ -0,0 +1,5 @@ +# Makefile for wificfg example +PROGRAM=wificfg +EXTRA_COMPONENTS=extras/dhcpserver extras/wificfg + +include ../../common.mk diff --git a/examples/wificfg/content/index.html b/examples/wificfg/content/index.html new file mode 100644 index 0000000..5512b7d --- /dev/null +++ b/examples/wificfg/content/index.html @@ -0,0 +1,18 @@ +"" +"" +"" +"" +"", +"" +"" +"" +"" +"", +"" diff --git a/examples/wificfg/local.mk b/examples/wificfg/local.mk new file mode 100644 index 0000000..c6c3129 --- /dev/null +++ b/examples/wificfg/local.mk @@ -0,0 +1 @@ +FLASH_SIZE ?= 32 diff --git a/examples/wificfg/wificfg.c b/examples/wificfg/wificfg.c new file mode 100644 index 0000000..a90a9da --- /dev/null +++ b/examples/wificfg/wificfg.c @@ -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 +#include + +#include +#include +#include +#include +#include + +#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, "
", 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, "
Peer address
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR " : %d
", + 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, "
", 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); +} diff --git a/extras/ad770x/ad770x.c b/extras/ad770x/ad770x.c new file mode 100644 index 0000000..0882d94 --- /dev/null +++ b/extras/ad770x/ad770x.c @@ -0,0 +1,181 @@ +/** + * Driver for AD7705/AD7706 SPI ADC + * + * Part of esp-open-rtos + * Copyright (C) 2017 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#include "ad770x.h" + +#include +#include +#include +#include + +#define AD770X_DEBUG + +#define BUS 1 +#define INIT_TIMEOUT 500000 // 500ms + +#ifdef AD770X_DEBUG +#include +#define debug(fmt, ...) printf("%s" fmt "\n", "AD770x: ", ## __VA_ARGS__) +#else +#define debug(fmt, ...) +#endif + +#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len)) + +#define _BV(x) (1 << (x)) + +#define REG_COMM 0x00 // 8 bits +#define REG_SETUP 0x01 // 8 bits +#define REG_CLOCK 0x02 // 8 bits +#define REG_DATA 0x03 // 16 bits +#define REG_TEST 0x04 // 8 bits +#define REG_OFFS 0x06 // 24 bits +#define REG_GAIN 0x07 // 24 bits + +#define BIT_COMM_CH0 0 +#define BIT_COMM_CH1 1 +#define BIT_COMM_STBY 2 +#define BIT_COMM_RW 3 +#define BIT_COMM_RS0 4 +#define BIT_COMM_RS1 5 +#define BIT_COMM_RS2 6 +#define BIT_COMM_DRDY 7 + +#define MASK_COMM_CH 0x03 +#define MASK_COMM_RS 0x70 + +#define BIT_CLOCK_FS0 0 +#define BIT_CLOCK_FS1 1 +#define BIT_CLOCK_CLK 2 +#define BIT_CLOCK_CLKDIV 3 +#define BIT_CLOCK_CLKDIS 4 + +#define MASK_CLOCK_FS 0x03 +#define MASK_CLOCK_CLK 0x0c + +#define BIT_SETUP_FSYNC 0 +#define BIT_SETUP_BUF 1 +#define BIT_SETUP_BU 2 +#define BIT_SETUP_G0 3 +#define BIT_SETUP_G1 4 +#define BIT_SETUP_G2 5 +#define BIT_SETUP_MD0 6 +#define BIT_SETUP_MD1 7 + +#define MASK_SETUP_GAIN 0x38 +#define MASK_SETUP_MODE 0xc0 + +static const spi_settings_t config = { + .endianness = SPI_BIG_ENDIAN, + .msb = true, + .minimal_pins = true, + .mode = SPI_MODE3, + .freq_divider = SPI_FREQ_DIV_500K +}; + +static uint8_t write(uint8_t cs_pin, uint8_t value) +{ + spi_settings_t old; + spi_get_settings(BUS, &old); + spi_set_settings(BUS, &config); + + gpio_write(cs_pin, false); + uint8_t res = spi_transfer_8(BUS, value); + //debug("byte wr: 0x%02x", value); + gpio_write(cs_pin, true); + + spi_set_settings(BUS, &old); + return res; +} + +inline static uint8_t read_byte(uint8_t cs_pin) +{ + return write(cs_pin, 0); +} + +static uint16_t read_word(uint8_t cs_pin) +{ + spi_settings_t old; + spi_get_settings(BUS, &old); + spi_set_settings(BUS, &config); + + gpio_write(cs_pin, false); + uint16_t res = spi_transfer_16(BUS, 0); + gpio_write(cs_pin, true); + + spi_set_settings(BUS, &old); + return res; +} + +static void prepare(uint8_t channel, uint8_t reg, bool read, uint8_t cs_pin, bool standby) +{ + write(cs_pin, + (channel & MASK_COMM_CH) | + (read ? _BV(BIT_COMM_RW) : 0) | + ((reg << BIT_COMM_RS0) & MASK_COMM_RS) | + (standby ? _BV(BIT_COMM_STBY) : 0) + ); +} + +int ad770x_init(const ad770x_params_t *params, uint8_t channel) +{ + if (!spi_set_settings(BUS, &config)) + { + debug("Cannot init SPI"); + return -EIO; + } + + if ((params->master_clock >= AD770X_MCLK_2_4576MHz && params->update_rate < AD770X_RATE_50) + || (params->master_clock < AD770X_MCLK_2_4576MHz && params->update_rate > AD770X_RATE_200)) + { + debug("Invalid update rate / master clock combination"); + return -EINVAL; + } + + gpio_enable(params->cs_pin, GPIO_OUTPUT); + gpio_write(params->cs_pin, true); + + prepare(channel, REG_CLOCK, false, params->cs_pin, false); + write(params->cs_pin, + ((params->master_clock << BIT_CLOCK_CLK) & MASK_CLOCK_CLK) | + (params->update_rate & MASK_CLOCK_FS) + ); + + ad770x_set_mode(params, channel, AD770X_MODE_CALIBRATION); + + uint32_t start = sdk_system_get_time(); + while (!ad770x_data_ready(params, channel)) + if (timeout_expired(start, INIT_TIMEOUT)) + { + debug("Timeout while calibration"); + return -EIO; + } + + return 0; +} + +void ad770x_set_mode(const ad770x_params_t *params, uint8_t channel, ad770x_mode_t mode) +{ + prepare(channel, REG_SETUP, false, params->cs_pin, false); + write(params->cs_pin, + ((params->gain << BIT_SETUP_G0) & MASK_SETUP_GAIN) | + (params->bipolar ? 0 : _BV(BIT_SETUP_BU)) | + ((mode << BIT_SETUP_MD0) & MASK_SETUP_MODE) + ); +} + +bool ad770x_data_ready(const ad770x_params_t *params, uint8_t channel) +{ + prepare(channel, REG_COMM, true, params->cs_pin, false); + return !(read_byte(params->cs_pin) & _BV(BIT_COMM_DRDY)); +} + +uint16_t ad770x_raw_adc_value(const ad770x_params_t *params, uint8_t channel) +{ + prepare(channel, REG_DATA, true, params->cs_pin, false); + return read_word(params->cs_pin); +} diff --git a/extras/ad770x/ad770x.h b/extras/ad770x/ad770x.h new file mode 100644 index 0000000..bfa2a98 --- /dev/null +++ b/extras/ad770x/ad770x.h @@ -0,0 +1,118 @@ +/** + * Driver for AD7705/AD7706 SPI ADC + * + * Part of esp-open-rtos + * Copyright (C) 2017 Ruslan V. Uss + * BSD Licensed as described in the file LICENSE + */ +#ifndef _EXTRAS_AD770X_H_ +#define _EXTRAS_AD770X_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Input gain + */ +typedef enum +{ + AD770X_GAIN_1 = 0, + AD770X_GAIN_2, + AD770X_GAIN_4, + AD770X_GAIN_8, + AD770X_GAIN_16, + AD770X_GAIN_32, + AD770X_GAIN_64, + AD770X_GAIN_128 +} ad770x_gain_t; + +/** + * Master clock frequency + */ +typedef enum +{ + AD770X_MCLK_1MHz = 0, //!< 1 MHz + AD770X_MCLK_2MHz, //!< 2 MHz + AD770X_MCLK_2_4576MHz, //!< 2.4576 MHz + AD770X_MCLK_4_9152MHz, //!< 4.9152 MHz +} ad770x_master_clock_t; + +/** + * Output update rate + */ +typedef enum +{ + AD770X_RATE_20 = 0, //!< Output update rate is 20 Hz, -3 dB filter cutoff = 5.24 Hz, works with 1 or 2 MHz master clock + AD770X_RATE_25, //!< Output update rate is 25 Hz, -3 dB filter cutoff = 6.55 Hz, works with 1 or 2 MHz master clock + AD770X_RATE_100, //!< Output update rate is 100 Hz, -3 dB filter cutoff = 26.2 Hz, works with 1 or 2 MHz master clock + AD770X_RATE_200, //!< Output update rate is 200 Hz, -3 dB filter cutoff = 52.4 Hz, works with 1 or 2 MHz master clock + AD770X_RATE_50, //!< Output update rate is 50 Hz, -3 dB filter cutoff = 13.1 Hz, works with 2.4576 or 4.9152 MHz master clock + AD770X_RATE_60, //!< Output update rate is 60 Hz, -3 dB filter cutoff = 15.7 Hz, works with 2.4576 or 4.9152 MHz master clock + AD770X_RATE_250, //!< Output update rate is 250 Hz, -3 dB filter cutoff = 65.5 Hz, works with 2.4576 or 4.9152 MHz master clock + AD770X_RATE_500, //!< Output update rate is 500 Hz, -3 dB filter cutoff = 131 Hz, works with 2.4576 or 4.9152 MHz master clock +} ad770x_update_rate_t; + +/** + * Device mode + */ +typedef enum +{ + AD770X_MODE_NORMAL = 0, + AD770X_MODE_CALIBRATION, + AD770X_MODE_ZERO_CALIBRATION, + AD770X_MODE_FULL_CALIBRATION +} ad770x_mode_t; + +/** + * Device descriptor + */ +typedef struct +{ + uint8_t cs_pin; //!< GPIO pin for chip select + ad770x_master_clock_t master_clock; //!< Master clock frequency + bool bipolar; //!< Bipolar/Unipolar mode + ad770x_gain_t gain; //!< Input gain + ad770x_update_rate_t update_rate; //!< Output update rate +} ad770x_params_t; + +/** + * Init device and setup channel params + * @param params Device descriptor pointer + * @param channel Input channel + * @return Non-zero when error occured + */ +int ad770x_init(const ad770x_params_t *params, uint8_t channel); + +/** + * Set device mode (see datasheet) + * @param params Device descriptor pointer + * @param channel Input channel + * @param mode Device mode + */ +void ad770x_set_mode(const ad770x_params_t *params, uint8_t channel, ad770x_mode_t mode); + +/** + * Get conversion status + * @param params Device descriptor pointer + * @param channel Input channel + * @return true when data is ready + */ +bool ad770x_data_ready(const ad770x_params_t *params, uint8_t channel); + +/** + * Get converted ADC value + * @param params Device descriptor pointer + * @param channel Input channel + * @return Raw ADC value + */ +uint16_t ad770x_raw_adc_value(const ad770x_params_t *params, uint8_t channel); + +#ifdef __cplusplus +} +#endif + +#endif /* _EXTRAS_AD770X_H_ */ diff --git a/extras/ad770x/component.mk b/extras/ad770x/component.mk new file mode 100644 index 0000000..a4d47f5 --- /dev/null +++ b/extras/ad770x/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/ad770x (AD7705/AD7706 driver) + +# expected anyone using ADC driver includes it as 'ad770x/ad770x.h' +INC_DIRS += $(ad770x_ROOT).. + +# args for passing into compile rule generation +ad770x_SRC_DIR = $(ad770x_ROOT) + +$(eval $(call component_compile_rules,ad770x)) diff --git a/extras/ads111x/ads111x.c b/extras/ads111x/ads111x.c index 9241e13..8e68ee4 100644 --- a/extras/ads111x/ads111x.c +++ b/extras/ads111x/ads111x.c @@ -6,7 +6,6 @@ * BSD Licensed as described in the file LICENSE */ #include "ads111x.h" -#include #define ADS111X_DEBUG @@ -52,144 +51,144 @@ const float ads111x_gain_values[] = { [ADS111X_GAIN_0V256_3] = 0.256 }; -static uint16_t read_reg(uint8_t addr, uint8_t reg) +static uint16_t read_reg(i2c_dev_t* dev, uint8_t reg) { uint16_t res = 0; - if (!i2c_slave_read(addr, reg, (uint8_t *)&res, 2)) + if (i2c_slave_read(dev->bus, dev->addr, ®, (uint8_t *)&res, 2)) debug("Could not read register %d", reg); //debug("Read %d: 0x%04x", reg, res); return res; } -static void write_reg(uint8_t addr, uint8_t reg, uint16_t val) +static void write_reg(i2c_dev_t* dev, uint8_t reg, uint16_t val) { //debug("Write %d: 0x%04x", reg, val); - uint8_t buf[3] = {reg, val >> 8, val}; - if (!i2c_slave_write(addr, buf, 3)) + uint8_t buf[2] = { val >> 8, val}; + if (i2c_slave_write(dev->bus, dev->addr, ®, buf, 2)) debug("Could not write 0x%04x to register %d", val, reg); } -static uint16_t read_conf_bits(uint8_t addr, uint8_t offs, uint16_t mask) +static uint16_t read_conf_bits(i2c_dev_t* dev, uint8_t offs, uint16_t mask) { - return (read_reg(addr, REG_CONFIG) >> offs) & mask; + return (read_reg(dev, REG_CONFIG) >> offs) & mask; } -static void write_conf_bits(uint8_t addr, uint16_t val, uint8_t offs, uint16_t mask) +static void write_conf_bits(i2c_dev_t* dev, uint16_t val, uint8_t offs, uint16_t mask) { - write_reg(addr, REG_CONFIG, (read_reg(addr, REG_CONFIG) & ~(mask << offs)) | (val << offs)); + write_reg(dev, REG_CONFIG, (read_reg(dev, REG_CONFIG) & ~(mask << offs)) | (val << offs)); } -bool ads111x_busy(uint8_t addr) +bool ads111x_busy(i2c_dev_t* dev) { - return read_conf_bits(addr, OS_OFFSET, OS_MASK); + return read_conf_bits(dev, OS_OFFSET, OS_MASK); } -void ads111x_start_conversion(uint8_t addr) +void ads111x_start_conversion(i2c_dev_t* dev) { - write_conf_bits(addr, 1, OS_OFFSET, OS_MASK); + write_conf_bits(dev, 1, OS_OFFSET, OS_MASK); } -int16_t ads111x_get_value(uint8_t addr) +int16_t ads111x_get_value(i2c_dev_t* dev) { - return read_reg(addr, REG_CONVERSION); + return read_reg(dev, REG_CONVERSION); } -ads111x_gain_t ads111x_get_gain(uint8_t addr) +ads111x_gain_t ads111x_get_gain(i2c_dev_t* dev) { - return read_conf_bits(addr, PGA_OFFSET, PGA_MASK); + return read_conf_bits(dev, PGA_OFFSET, PGA_MASK); } -void ads111x_set_gain(uint8_t addr, ads111x_gain_t gain) +void ads111x_set_gain(i2c_dev_t* dev, ads111x_gain_t gain) { - write_conf_bits(addr, gain, PGA_OFFSET, PGA_MASK); + write_conf_bits(dev, gain, PGA_OFFSET, PGA_MASK); } -ads111x_mux_t ads111x_get_input_mux(uint8_t addr) +ads111x_mux_t ads111x_get_input_mux(i2c_dev_t* dev) { - return read_conf_bits(addr, MUX_OFFSET, MUX_MASK); + return read_conf_bits(dev, MUX_OFFSET, MUX_MASK); } -void ads111x_set_input_mux(uint8_t addr, ads111x_mux_t mux) +void ads111x_set_input_mux(i2c_dev_t* dev, ads111x_mux_t mux) { - write_conf_bits(addr, mux, MUX_OFFSET, MUX_MASK); + write_conf_bits(dev, mux, MUX_OFFSET, MUX_MASK); } -ads111x_mode_t ads111x_get_mode(uint8_t addr) +ads111x_mode_t ads111x_get_mode(i2c_dev_t* dev) { - return read_conf_bits(addr, MODE_OFFSET, MODE_MASK); + return read_conf_bits(dev, MODE_OFFSET, MODE_MASK); } -void ads111x_set_mode(uint8_t addr, ads111x_mode_t mode) +void ads111x_set_mode(i2c_dev_t* dev, ads111x_mode_t mode) { - write_conf_bits(addr, mode, MODE_OFFSET, MODE_MASK); + write_conf_bits(dev, mode, MODE_OFFSET, MODE_MASK); } -ads111x_data_rate_t ads111x_get_data_rate(uint8_t addr) +ads111x_data_rate_t ads111x_get_data_rate(i2c_dev_t* dev) { - return read_conf_bits(addr, DR_OFFSET, DR_MASK); + return read_conf_bits(dev, DR_OFFSET, DR_MASK); } -void ads111x_set_data_rate(uint8_t addr, ads111x_data_rate_t rate) +void ads111x_set_data_rate(i2c_dev_t* dev, ads111x_data_rate_t rate) { - write_conf_bits(addr, rate, DR_OFFSET, DR_MASK); + write_conf_bits(dev, rate, DR_OFFSET, DR_MASK); } -ads111x_comp_mode_t ads111x_get_comp_mode(uint8_t addr) +ads111x_comp_mode_t ads111x_get_comp_mode(i2c_dev_t* dev) { - return read_conf_bits(addr, COMP_MODE_OFFSET, COMP_MODE_MASK); + return read_conf_bits(dev, COMP_MODE_OFFSET, COMP_MODE_MASK); } -void ads111x_set_comp_mode(uint8_t addr, ads111x_comp_mode_t mode) +void ads111x_set_comp_mode(i2c_dev_t* dev, ads111x_comp_mode_t mode) { - write_conf_bits(addr, mode, COMP_MODE_OFFSET, COMP_MODE_MASK); + write_conf_bits(dev, mode, COMP_MODE_OFFSET, COMP_MODE_MASK); } -ads111x_comp_polarity_t ads111x_get_comp_polarity(uint8_t addr) +ads111x_comp_polarity_t ads111x_get_comp_polarity(i2c_dev_t* dev) { - return read_conf_bits(addr, COMP_POL_OFFSET, COMP_POL_MASK); + return read_conf_bits(dev, COMP_POL_OFFSET, COMP_POL_MASK); } -void ads111x_set_comp_polarity(uint8_t addr, ads111x_comp_polarity_t polarity) +void ads111x_set_comp_polarity(i2c_dev_t* dev, ads111x_comp_polarity_t polarity) { - write_conf_bits(addr, polarity, COMP_POL_OFFSET, COMP_POL_MASK); + write_conf_bits(dev, polarity, COMP_POL_OFFSET, COMP_POL_MASK); } -ads111x_comp_latch_t ads111x_get_comp_latch(uint8_t addr) +ads111x_comp_latch_t ads111x_get_comp_latch(i2c_dev_t* dev) { - return read_conf_bits(addr, COMP_LAT_OFFSET, COMP_LAT_MASK); + return read_conf_bits(dev, COMP_LAT_OFFSET, COMP_LAT_MASK); } -void ads111x_set_comp_latch(uint8_t addr, ads111x_comp_latch_t latch) +void ads111x_set_comp_latch(i2c_dev_t* dev, ads111x_comp_latch_t latch) { - write_conf_bits(addr, latch, COMP_LAT_OFFSET, COMP_LAT_MASK); + write_conf_bits(dev, latch, COMP_LAT_OFFSET, COMP_LAT_MASK); } -ads111x_comp_queue_t ads111x_get_comp_queue(uint8_t addr) +ads111x_comp_queue_t ads111x_get_comp_queue(i2c_dev_t* dev) { - return read_conf_bits(addr, COMP_QUE_OFFSET, COMP_QUE_MASK); + return read_conf_bits(dev, COMP_QUE_OFFSET, COMP_QUE_MASK); } -void ads111x_set_comp_queue(uint8_t addr, ads111x_comp_queue_t queue) +void ads111x_set_comp_queue(i2c_dev_t* dev, ads111x_comp_queue_t queue) { - write_conf_bits(addr, queue, COMP_QUE_OFFSET, COMP_QUE_MASK); + write_conf_bits(dev, queue, COMP_QUE_OFFSET, COMP_QUE_MASK); } -int16_t ads111x_get_comp_low_thresh(uint8_t addr) +int16_t ads111x_get_comp_low_thresh(i2c_dev_t* dev) { - return read_reg(addr, REG_THRESH_L); + return read_reg(dev, REG_THRESH_L); } -void ads111x_set_comp_low_thresh(uint8_t addr, int16_t thresh) +void ads111x_set_comp_low_thresh(i2c_dev_t* dev, int16_t thresh) { - write_reg(addr, REG_THRESH_L, thresh); + write_reg(dev, REG_THRESH_L, thresh); } -int16_t ads111x_get_comp_high_thresh(uint8_t addr) +int16_t ads111x_get_comp_high_thresh(i2c_dev_t* dev) { - return read_reg(addr, REG_THRESH_H); + return read_reg(dev, REG_THRESH_H); } -void ads111x_set_comp_high_thresh(uint8_t addr, int16_t thresh) +void ads111x_set_comp_high_thresh(i2c_dev_t* dev, int16_t thresh) { - write_reg(addr, REG_THRESH_H, thresh); + write_reg(dev, REG_THRESH_H, thresh); } diff --git a/extras/ads111x/ads111x.h b/extras/ads111x/ads111x.h index fe64464..af93d4e 100644 --- a/extras/ads111x/ads111x.h +++ b/extras/ads111x/ads111x.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -124,20 +125,20 @@ typedef enum * @param addr Deivce address * @return true when device performing conversion */ -bool ads111x_busy(uint8_t addr); +bool ads111x_busy(i2c_dev_t* dev); /** * Begin a single conversion (when in single-shot mode) * @param addr Deivce address */ -void ads111x_start_conversion(uint8_t addr); +void ads111x_start_conversion(i2c_dev_t* dev); /** * Read last conversion result * @param addr * @return Last conversion result */ -int16_t ads111x_get_value(uint8_t addr); +int16_t ads111x_get_value(i2c_dev_t* dev); /** * Read the programmable gain amplifier configuration @@ -145,70 +146,70 @@ int16_t ads111x_get_value(uint8_t addr); * @param addr Deivce address * @return Gain value */ -ads111x_gain_t ads111x_get_gain(uint8_t addr); +ads111x_gain_t ads111x_get_gain(i2c_dev_t* dev); /** * Configure the programmable gain amplifier (ADS1114 and ADS1115 only) * @param addr Deivce address * @param gain Gain value */ -void ads111x_set_gain(uint8_t addr, ads111x_gain_t gain); +void ads111x_set_gain(i2c_dev_t* dev, ads111x_gain_t gain); /** * Read the input multiplexer configuration (ADS1115 only) * @param addr Deivce address * @return Input multiplexer configuration */ -ads111x_mux_t ads111x_get_input_mux(uint8_t addr); +ads111x_mux_t ads111x_get_input_mux(i2c_dev_t* dev); /** * Configure the input multiplexer configuration (ADS1115 only) * @param addr Deivce address * @param mux Input multiplexer configuration */ -void ads111x_set_input_mux(uint8_t addr, ads111x_mux_t mux); +void ads111x_set_input_mux(i2c_dev_t* dev, ads111x_mux_t mux); /** * Read the device operating mode * @param addr Deivce address * @return Device operating mode */ -ads111x_mode_t ads111x_get_mode(uint8_t addr); +ads111x_mode_t ads111x_get_mode(i2c_dev_t* dev); /** * Set the device operating mode * @param addr Deivce address * @param mode Device operating mode */ -void ads111x_set_mode(uint8_t addr, ads111x_mode_t mode); +void ads111x_set_mode(i2c_dev_t* dev, ads111x_mode_t mode); /** * Read the data rate * @param addr Deivce address * @return Data rate */ -ads111x_data_rate_t ads111x_get_data_rate(uint8_t addr); +ads111x_data_rate_t ads111x_get_data_rate(i2c_dev_t* dev); /** * Configure the data rate * @param addr Deivce address * @param rate Data rate */ -void ads111x_set_data_rate(uint8_t addr, ads111x_data_rate_t rate); +void ads111x_set_data_rate(i2c_dev_t* dev, ads111x_data_rate_t rate); /** * Get comparator mode (ADS1114 and ADS1115 only) * @param addr Deivce address * @return Comparator mode */ -ads111x_comp_mode_t ads111x_get_comp_mode(uint8_t addr); +ads111x_comp_mode_t ads111x_get_comp_mode(i2c_dev_t* dev); /** * Set comparator mode (ADS1114 and ADS1115 only) * @param addr Deivce address * @param mode Comparator mode */ -void ads111x_set_comp_mode(uint8_t addr, ads111x_comp_mode_t mode); +void ads111x_set_comp_mode(i2c_dev_t* dev, ads111x_comp_mode_t mode); /** * Get polarity of the comparator output pin ALERT/RDY @@ -216,7 +217,7 @@ void ads111x_set_comp_mode(uint8_t addr, ads111x_comp_mode_t mode); * @param addr Deivce address * @return Comparator output pin polarity */ -ads111x_comp_polarity_t ads111x_get_comp_polarity(uint8_t addr); +ads111x_comp_polarity_t ads111x_get_comp_polarity(i2c_dev_t* dev); /** * Set polarity of the comparator output pin ALERT/RDY @@ -224,7 +225,7 @@ ads111x_comp_polarity_t ads111x_get_comp_polarity(uint8_t addr); * @param addr Deivce address * @param polarity Comparator output pin polarity */ -void ads111x_set_comp_polarity(uint8_t addr, ads111x_comp_polarity_t polarity); +void ads111x_set_comp_polarity(i2c_dev_t* dev, ads111x_comp_polarity_t polarity); /** * Get comparator output latch mode, see datasheet. @@ -232,14 +233,14 @@ void ads111x_set_comp_polarity(uint8_t addr, ads111x_comp_polarity_t polarity); * @param addr Deivce address * @return Comparator output latch mode */ -ads111x_comp_latch_t ads111x_get_comp_latch(uint8_t addr); +ads111x_comp_latch_t ads111x_get_comp_latch(i2c_dev_t* dev); /** * Set comparator output latch mode (ADS1114 and ADS1115 only) * @param addr Deivce address * @param latch Comparator output latch mode */ -void ads111x_set_comp_latch(uint8_t addr, ads111x_comp_latch_t latch); +void ads111x_set_comp_latch(i2c_dev_t* dev, ads111x_comp_latch_t latch); /** * Set number of the comparator conversions before pin ALERT/RDY @@ -247,7 +248,7 @@ void ads111x_set_comp_latch(uint8_t addr, ads111x_comp_latch_t latch); * @param addr Deivce address * @return Number of the comparator conversions */ -ads111x_comp_queue_t ads111x_get_comp_queue(uint8_t addr); +ads111x_comp_queue_t ads111x_get_comp_queue(i2c_dev_t* dev); /** * Get number of the comparator conversions before pin ALERT/RDY @@ -255,35 +256,35 @@ ads111x_comp_queue_t ads111x_get_comp_queue(uint8_t addr); * @param addr Deivce address * @param queue Number of the comparator conversions */ -void ads111x_set_comp_queue(uint8_t addr, ads111x_comp_queue_t queue); +void ads111x_set_comp_queue(i2c_dev_t* dev, ads111x_comp_queue_t queue); /** * Get the lower threshold value used by comparator * @param addr Deivce address * @return Lower threshold value */ -int16_t ads111x_get_comp_low_thresh(uint8_t addr); +int16_t ads111x_get_comp_low_thresh(i2c_dev_t* dev); /** * Set the lower threshold value used by comparator * @param addr Deivce address * @param thresh Lower threshold value */ -void ads111x_set_comp_low_thresh(uint8_t addr, int16_t thresh); +void ads111x_set_comp_low_thresh(i2c_dev_t* dev, int16_t thresh); /** * Get the upper threshold value used by comparator * @param addr Deivce address * @return Upper threshold value */ -int16_t ads111x_get_comp_high_thresh(uint8_t addr); +int16_t ads111x_get_comp_high_thresh(i2c_dev_t* dev); /** * Set the upper threshold value used by comparator * @param addr Deivce address * @param thresh Upper threshold value */ -void ads111x_set_comp_high_thresh(uint8_t addr, int16_t thresh); +void ads111x_set_comp_high_thresh(i2c_dev_t* dev, int16_t thresh); #ifdef __cplusplus } diff --git a/extras/bearssl/BearSSL b/extras/bearssl/BearSSL index f0c0046..2b73849 160000 --- a/extras/bearssl/BearSSL +++ b/extras/bearssl/BearSSL @@ -1 +1 @@ -Subproject commit f0c00466018e4bcdaa2d965ac723d53f015cde9a +Subproject commit 2b738493bd16d57fdb12d38d03631981370259be diff --git a/extras/bh1750/bh1750.c b/extras/bh1750/bh1750.c new file mode 100644 index 0000000..51860d0 --- /dev/null +++ b/extras/bh1750/bh1750.c @@ -0,0 +1,27 @@ +/* + * Driver for BH1750 light sensor + * + * Part of esp-open-rtos + * Copyright (C) 2017 Andrej Krutak + * BSD Licensed as described in the file LICENSE + */ +#include "bh1750.h" +#include + +void bh1750_configure(i2c_dev_t *dev, uint8_t mode) +{ + i2c_slave_write(dev->bus, dev->addr, NULL, &mode, 1); +} + +uint16_t bh1750_read(i2c_dev_t *dev) +{ + uint8_t buf[2]; + uint16_t level; + + i2c_slave_read(dev->bus, dev->addr, NULL, buf, 2); + + level = buf[0] << 8 | buf[1]; + level = (level * 10) / 12; // convert to LUX + + return level; +} diff --git a/extras/bh1750/bh1750.h b/extras/bh1750/bh1750.h new file mode 100644 index 0000000..a6bcae6 --- /dev/null +++ b/extras/bh1750/bh1750.h @@ -0,0 +1,83 @@ +/* + * Driver for BH1750 light sensor + * + * Part of esp-open-rtos + * Copyright (C) 2017 Andrej Krutak + * BSD Licensed as described in the file LICENSE + * + * ROHM Semiconductor bh1750fvi-e.pdf + */ +#ifndef EXTRAS_BH1750_H_ +#define EXTRAS_BH1750_H_ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Possible chip addresses */ +#define BH1750_ADDR_LO 0x23 // ADDR pin floating/low +#define BH1750_ADDR_HI 0x5c + + +/* Configuration options */ + +// No active state +#define BH1750_POWER_DOWN 0x00 + +// Wating for measurement command +#define BH1750_POWER_ON 0x01 + +// Reset data register value - not accepted in POWER_DOWN mode +#define BH1750_RESET 0x07 + + +/* Measurement modes */ + +#define BH1750_CONTINUOUS_MODE 0x10 +#define BH1750_ONE_TIME_MODE 0x20 + +// Start measurement at 1 lx resolution (measurement time typically 120ms) +#define BH1750_HIGH_RES_MODE 0x00 +// Start measurement at 0.5 lx resolution (measurement time typically 120ms) +#define BH1750_HIGH_RES_MODE2 0x01 +// Start measurement at 4 lx resolution (measurement time typically 16ms) +#define BH1750_LOW_RES_MODE 0x03 + +/* Adjust measurement time to account for optical window size (see datasheet). + * Procedure from datasheet suggests order Hi, Low and finally measurement mode + */ +#define BH1750_MEASURE_TIME_HI(mt) (0x40 | (((mt) >> 5) & 0x7)) +#define BH1750_MEASURE_TIME_LO(mt) (0x60 | ((mt) & 0x1f)) +#define BH1750_DEFAULT_MEASURE_TIME 0x45 + + +/** + * Configure the device. + * @param addr Device address + * @param mode Combination of BH1750_* flags + * + * May be called multiple times e.g. to configure the measurement time and + * the readout mode afterwards - or if one time mode is used consecutively. + * + * Example: BH1750_ADDR_LO, BH1750_CONTINUOUS_MODE | BH1750_HIGH_RES_MODE + */ +void bh1750_configure(i2c_dev_t *dev, uint8_t mode); + +/** + * Read LUX value from the device. + * + * @param addr Device address + * @returns read value in lux units + */ +uint16_t bh1750_read(i2c_dev_t *dev); + +#ifdef __cplusplus +} +#endif + +#endif /* EXTRAS_BH1750_H_ */ diff --git a/extras/bh1750/component.mk b/extras/bh1750/component.mk new file mode 100644 index 0000000..0a57b31 --- /dev/null +++ b/extras/bh1750/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/bh1750 + +# expected anyone using RTC driver includes it as 'bh1750/bh1750.h' +INC_DIRS += $(bh1750_ROOT).. + +# args for passing into compile rule generation +bh1750_SRC_DIR = $(bh1750_ROOT) + +$(eval $(call component_compile_rules,bh1750)) diff --git a/extras/bmp180/bmp180.c b/extras/bmp180/bmp180.c index c3c8afd..d7d4330 100644 --- a/extras/bmp180/bmp180.c +++ b/extras/bmp180/bmp180.c @@ -7,13 +7,9 @@ #include "espressif/esp_common.h" #include "espressif/sdk_private.h" -#include "i2c/i2c.h" - #define BMP180_RX_QUEUE_SIZE 10 #define BMP180_TASK_PRIORITY 9 -#define BMP180_DEVICE_ADDRESS 0x77 - #define BMP180_VERSION_REG 0xD0 #define BMP180_CONTROL_REG 0xF4 #define BMP180_RESET_REG 0xE0 @@ -39,42 +35,43 @@ // #define BMP180_RESET_VALUE 0xB6 -static bool bmp180_readRegister16(uint8_t reg, int16_t *r) +static int bmp180_readRegister16(i2c_dev_t *dev, uint8_t reg, int16_t *r) { uint8_t d[] = { 0, 0 }; + int error ; - if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, reg, d, 2)) - return false; + if ((error = i2c_slave_read(dev->bus, dev->addr, ®, d, 2))) + return error; *r = ((int16_t)d[0] << 8) | (d[1]); - return true; + return 0; } -static bool bmp180_start_Messurement(uint8_t cmd) +static int bmp180_start_Messurement(i2c_dev_t *dev, uint8_t cmd) { - uint8_t d[] = { BMP180_CONTROL_REG, cmd }; + uint8_t reg = BMP180_CONTROL_REG ; - return i2c_slave_write(BMP180_DEVICE_ADDRESS, d, 2); + return i2c_slave_write(dev->bus, dev->addr, ®, &cmd, 1); } -static bool bmp180_get_uncompensated_temperature(int32_t *ut) +static bool bmp180_get_uncompensated_temperature(i2c_dev_t *dev, int32_t *ut) { // Write Start Code into reg 0xF4. - if (!bmp180_start_Messurement(BMP180_MEASURE_TEMP)) + if (bmp180_start_Messurement(dev, BMP180_MEASURE_TEMP)) return false; // Wait 5ms, datasheet states 4.5ms sdk_os_delay_us(5000); int16_t v; - if (!bmp180_readRegister16(BMP180_OUT_MSB_REG, &v)) + if (bmp180_readRegister16(dev, BMP180_OUT_MSB_REG, &v)) return false; *ut = v; return true; } -static bool bmp180_get_uncompensated_pressure(uint8_t oss, uint32_t *up) +static bool bmp180_get_uncompensated_pressure(i2c_dev_t *dev, uint8_t oss, uint32_t *up) { uint16_t us; @@ -88,13 +85,14 @@ static bool bmp180_get_uncompensated_pressure(uint8_t oss, uint32_t *up) } // Write Start Code into reg 0xF4 - if (!bmp180_start_Messurement(BMP180_MEASURE_PRESS | (oss << 6))) + if (bmp180_start_Messurement(dev, BMP180_MEASURE_PRESS | (oss << 6))) return false; sdk_os_delay_us(us); uint8_t d[] = { 0, 0, 0 }; - if (!i2c_slave_read(BMP180_DEVICE_ADDRESS, BMP180_OUT_MSB_REG, d, 3)) + uint8_t reg = BMP180_OUT_MSB_REG; + if (i2c_slave_read(dev->bus, dev->addr, ®, d, 3)) return false; uint32_t r = ((uint32_t)d[0] << 16) | ((uint32_t)d[1] << 8) | d[2]; @@ -104,19 +102,19 @@ static bool bmp180_get_uncompensated_pressure(uint8_t oss, uint32_t *up) } // Returns true of success else false. -bool bmp180_fillInternalConstants(bmp180_constants_t *c) +bool bmp180_fillInternalConstants(i2c_dev_t *dev, bmp180_constants_t *c) { - if (!bmp180_readRegister16(BMP180_CALIBRATION_REG+0, &c->AC1) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+2, &c->AC2) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+4, &c->AC3) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+6, (int16_t *)&c->AC4) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+8, (int16_t *)&c->AC5) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+10, (int16_t *)&c->AC6) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+12, &c->B1) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+14, &c->B2) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+16, &c->MB) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+18, &c->MC) || - !bmp180_readRegister16(BMP180_CALIBRATION_REG+20, &c->MD)) { + if (bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+0, &c->AC1) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+2, &c->AC2) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+4, &c->AC3) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+6, (int16_t *)&c->AC4) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+8, (int16_t *)&c->AC5) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+10, (int16_t *)&c->AC6) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+12, &c->B1) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+14, &c->B2) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+16, &c->MB) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+18, &c->MC) || + bmp180_readRegister16(dev, BMP180_CALIBRATION_REG+20, &c->MD)) { return false; } @@ -137,14 +135,16 @@ bool bmp180_fillInternalConstants(bmp180_constants_t *c) c->MB == 0xffff || c->MC == 0xffff || c->MD == 0xffff); } -bool bmp180_is_available() +bool bmp180_is_available(i2c_dev_t *dev) { uint8_t id; - return i2c_slave_read(BMP180_DEVICE_ADDRESS, BMP180_VERSION_REG, &id, 1) && - id == BMP180_CHIP_ID; + uint8_t reg = BMP180_VERSION_REG; + if (i2c_slave_read(dev->bus, dev->addr, ®, &id, 1)) + return false; + return id == BMP180_CHIP_ID; } -bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature, +bool bmp180_measure(i2c_dev_t *dev, bmp180_constants_t *c, int32_t *temperature, uint32_t *pressure, uint8_t oss) { int32_t T, P; @@ -152,11 +152,11 @@ bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature, if (!temperature && !pressure) 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 int32_t UT, X1, X2, B5; - if (!bmp180_get_uncompensated_temperature(&UT)) + if (!bmp180_get_uncompensated_temperature(dev, &UT)) return false; X1 = ((UT - (int32_t)c->AC6) * (int32_t)c->AC5) >> 15; @@ -173,7 +173,7 @@ bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature, int32_t X3, B3, B6; uint32_t B4, B7, UP; - if (!bmp180_get_uncompensated_pressure(oss, &UP)) + if (!bmp180_get_uncompensated_pressure(dev, oss, &UP)) return false; // Calculation taken from BMP180 Datasheet @@ -208,8 +208,6 @@ bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature, return true; } - - // BMP180_Event_Command typedef struct { @@ -218,8 +216,8 @@ typedef struct } bmp180_command_t; // Just works due to the fact that QueueHandle_t is a "void *" -static QueueHandle_t bmp180_rx_queue = NULL; -static TaskHandle_t bmp180_task_handle = NULL; +static QueueHandle_t bmp180_rx_queue[MAX_I2C_BUS] = { NULL }; +static TaskHandle_t bmp180_task_handle[MAX_I2C_BUS] = { NULL }; // // Forward declarations @@ -235,6 +233,7 @@ static void bmp180_driver_task(void *pvParameters) // Data to be received from user bmp180_command_t current_command; bmp180_constants_t bmp180_constants; + i2c_dev_t *dev = (i2c_dev_t*)pvParameters; #ifdef BMP180_DEBUG // Wait for commands from the outside @@ -242,14 +241,14 @@ static void bmp180_driver_task(void *pvParameters) #endif // Initialize all internal constants. - if (!bmp180_fillInternalConstants(&bmp180_constants)) { + if (!bmp180_fillInternalConstants(dev, &bmp180_constants)) { printf("%s: reading internal constants failed\n", __FUNCTION__); vTaskDelete(NULL); } while(1) { // Wait for user to insert commands - if (xQueueReceive(bmp180_rx_queue, ¤t_command, portMAX_DELAY) == pdTRUE) { + if (xQueueReceive(bmp180_rx_queue[dev->bus], ¤t_command, portMAX_DELAY) == pdTRUE) { #ifdef BMP180_DEBUG printf("%s: Received user command %d 0x%p\n", __FUNCTION__, current_command.cmd, current_command.resultQueue); #endif @@ -259,7 +258,7 @@ static void bmp180_driver_task(void *pvParameters) int32_t T = 0; uint32_t P = 0; - if (bmp180_measure(&bmp180_constants, &T, (current_command.cmd & BMP180_PRESSURE) ? &P : NULL, 3)) { + if (bmp180_measure(dev, &bmp180_constants, &T, (current_command.cmd & BMP180_PRESSURE) ? &P : NULL, 3)) { // Inform the user ... if (!bmp180_informUser(current_command.resultQueue, current_command.cmd, @@ -274,22 +273,22 @@ static void bmp180_driver_task(void *pvParameters) } } -static bool bmp180_create_communication_queues() +static bool bmp180_create_communication_queues(i2c_dev_t *dev) { - // Just create them once - if (bmp180_rx_queue == NULL) - bmp180_rx_queue = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t)); + // Just create them once by bus + if (bmp180_rx_queue[dev->bus] == NULL) + bmp180_rx_queue[dev->bus] = xQueueCreate(BMP180_RX_QUEUE_SIZE, sizeof(bmp180_result_t)); - return bmp180_rx_queue != NULL; + return bmp180_rx_queue[dev->bus] != NULL; } -static bool bmp180_createTask() +static bool bmp180_createTask(i2c_dev_t *dev) { // We already have a task portBASE_TYPE x = pdPASS; - if (bmp180_task_handle == NULL) { - x = xTaskCreate(bmp180_driver_task, "bmp180_driver_task", 256, NULL, BMP180_TASK_PRIORITY, &bmp180_task_handle); + if (bmp180_task_handle[dev->bus] == NULL) { + x = xTaskCreate(bmp180_driver_task, "bmp180_driver_task", 256, (void*)dev, BMP180_TASK_PRIORITY, &bmp180_task_handle[dev->bus]); //TODO: name task with i2c bus } return x == pdPASS; } @@ -307,54 +306,51 @@ static bool bmp180_informUser_Impl(const QueueHandle_t* resultQueue, uint8_t cmd } // Just init all needed queues -bool bmp180_init(uint8_t scl, uint8_t sda) +bool bmp180_init(i2c_dev_t *dev) { // 1. Create required queues bool result = false; - if (bmp180_create_communication_queues()) { - // 2. Init i2c driver - i2c_init(scl, sda); - // 3. Check for bmp180 ... - if (bmp180_is_available()) { - // 4. Start driver task - if (bmp180_createTask()) { + if (bmp180_create_communication_queues(dev)) { + // 2. Check for bmp180 ... + if (bmp180_is_available(dev)) { + // 3. Start driver task + if (bmp180_createTask(dev)) { // We are finished result = true; } } } - return result; } -void bmp180_trigger_measurement(const QueueHandle_t* resultQueue) +void bmp180_trigger_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue) { bmp180_command_t c; c.cmd = BMP180_PRESSURE + BMP180_TEMPERATURE; c.resultQueue = resultQueue; - xQueueSend(bmp180_rx_queue, &c, 0); + xQueueSend(bmp180_rx_queue[dev->bus], &c, 0); } -void bmp180_trigger_pressure_measurement(const QueueHandle_t* resultQueue) +void bmp180_trigger_pressure_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue) { bmp180_command_t c; c.cmd = BMP180_PRESSURE; c.resultQueue = resultQueue; - xQueueSend(bmp180_rx_queue, &c, 0); + xQueueSend(bmp180_rx_queue[dev->bus], &c, 0); } -void bmp180_trigger_temperature_measurement(const QueueHandle_t* resultQueue) +void bmp180_trigger_temperature_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue) { bmp180_command_t c; c.cmd = BMP180_TEMPERATURE; c.resultQueue = resultQueue; - xQueueSend(bmp180_rx_queue, &c, 0); + xQueueSend(bmp180_rx_queue[dev->bus], &c, 0); } diff --git a/extras/bmp180/bmp180.h b/extras/bmp180/bmp180.h index 2f46150..a29a1ae 100644 --- a/extras/bmp180/bmp180.h +++ b/extras/bmp180/bmp180.h @@ -14,9 +14,13 @@ #include "FreeRTOS.h" #include "queue.h" +#include "i2c/i2c.h" + // Uncomment to enable debug output //#define BMP180_DEBUG +#define BMP180_DEVICE_ADDRESS 0x77 + #define BMP180_TEMPERATURE (1<<0) #define BMP180_PRESSURE (1<<1) @@ -42,16 +46,16 @@ typedef struct } bmp180_result_t; // Init bmp180 driver ... -bool bmp180_init(uint8_t scl, uint8_t sda); +bool bmp180_init(i2c_dev_t *dev); // Trigger a "complete" measurement (temperature and pressure will be valid when given to "bmp180_informUser) -void bmp180_trigger_measurement(const QueueHandle_t* resultQueue); +void bmp180_trigger_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue); // Trigger a "temperature only" measurement (only temperature will be valid when given to "bmp180_informUser) -void bmp180_trigger_temperature_measurement(const QueueHandle_t* resultQueue); +void bmp180_trigger_temperature_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue); // Trigger a "pressure only" measurement (only pressure will be valid when given to "bmp180_informUser) -void bmp180_trigger_pressure_measurement(const QueueHandle_t* resultQueue); +void bmp180_trigger_pressure_measurement(i2c_dev_t *dev, const QueueHandle_t* resultQueue); // Give the user the chance to create it's own handler extern bool (*bmp180_informUser)(const QueueHandle_t* resultQueue, uint8_t cmd, bmp180_temp_t temperature, bmp180_press_t pressure); @@ -75,12 +79,12 @@ typedef struct } bmp180_constants_t; // Returns true if the bmp180 is detected. -bool bmp180_is_available(); +bool bmp180_is_available(i2c_dev_t *dev); // Reads all the internal constants, returning true on success. -bool bmp180_fillInternalConstants(bmp180_constants_t *c); +bool bmp180_fillInternalConstants(i2c_dev_t *dev, bmp180_constants_t *c); // Reads an optional temperature and pressure. The over sampling // setting, oss, may be 0 to 3. Returns true on success. -bool bmp180_measure(bmp180_constants_t *c, int32_t *temperature, +bool bmp180_measure(i2c_dev_t *dev, bmp180_constants_t *c, int32_t *temperature, uint32_t *pressure, uint8_t oss); #ifdef __cplusplus diff --git a/extras/bmp280/bmp280.c b/extras/bmp280/bmp280.c index 83fdfe0..abff6fd 100644 --- a/extras/bmp280/bmp280.c +++ b/extras/bmp280/bmp280.c @@ -23,7 +23,6 @@ */ #include #include "bmp280.h" -#include "i2c/i2c.h" #ifdef BMP280_DEBUG #include @@ -66,32 +65,36 @@ void bmp280_init_default_params(bmp280_params_t *params) params->standby = BMP280_STANDBY_250; } -static bool read_register16(uint8_t i2c_addr, uint8_t addr, uint16_t *value) +static bool read_register16(i2c_dev_t* dev, uint8_t addr, uint16_t *value) { uint8_t d[] = {0, 0}; - if (i2c_slave_read(i2c_addr, addr, d, sizeof(d))) { + if (!i2c_slave_read(dev->bus, dev->addr, &addr, d, sizeof(d))) { *value = d[0] | (d[1] << 8); return true; } return false; } +static inline int read_data(i2c_dev_t* dev, uint8_t addr, uint8_t *value, uint8_t len) +{ + return i2c_slave_read(dev->bus, dev->addr, &addr, value, len); +} + static bool read_calibration_data(bmp280_t *dev) { - uint8_t i2c_addr = dev->i2c_addr; - if (read_register16(i2c_addr, 0x88, &dev->dig_T1) && - read_register16(i2c_addr, 0x8a, (uint16_t *)&dev->dig_T2) && - read_register16(i2c_addr, 0x8c, (uint16_t *)&dev->dig_T3) && - read_register16(i2c_addr, 0x8e, &dev->dig_P1) && - read_register16(i2c_addr, 0x90, (uint16_t *)&dev->dig_P2) && - read_register16(i2c_addr, 0x92, (uint16_t *)&dev->dig_P3) && - read_register16(i2c_addr, 0x94, (uint16_t *)&dev->dig_P4) && - read_register16(i2c_addr, 0x96, (uint16_t *)&dev->dig_P5) && - read_register16(i2c_addr, 0x98, (uint16_t *)&dev->dig_P6) && - read_register16(i2c_addr, 0x9a, (uint16_t *)&dev->dig_P7) && - read_register16(i2c_addr, 0x9c, (uint16_t *)&dev->dig_P8) && - read_register16(i2c_addr, 0x9e, (uint16_t *)&dev->dig_P9)) { + if (read_register16(&dev->i2c_dev, 0x88, &dev->dig_T1) && + read_register16(&dev->i2c_dev, 0x8a, (uint16_t *)&dev->dig_T2) && + read_register16(&dev->i2c_dev, 0x8c, (uint16_t *)&dev->dig_T3) && + read_register16(&dev->i2c_dev, 0x8e, &dev->dig_P1) && + read_register16(&dev->i2c_dev, 0x90, (uint16_t *)&dev->dig_P2) && + read_register16(&dev->i2c_dev, 0x92, (uint16_t *)&dev->dig_P3) && + read_register16(&dev->i2c_dev, 0x94, (uint16_t *)&dev->dig_P4) && + read_register16(&dev->i2c_dev, 0x96, (uint16_t *)&dev->dig_P5) && + read_register16(&dev->i2c_dev, 0x98, (uint16_t *)&dev->dig_P6) && + read_register16(&dev->i2c_dev, 0x9a, (uint16_t *)&dev->dig_P7) && + read_register16(&dev->i2c_dev, 0x9c, (uint16_t *)&dev->dig_P8) && + read_register16(&dev->i2c_dev, 0x9e, (uint16_t *)&dev->dig_P9)) { debug("Calibration data received:"); debug("dig_T1=%d", dev->dig_T1); @@ -115,15 +118,14 @@ static bool read_calibration_data(bmp280_t *dev) static bool read_hum_calibration_data(bmp280_t *dev) { - uint8_t i2c_addr = dev->i2c_addr; uint16_t h4, h5; - if (i2c_slave_read(i2c_addr, 0xa1, &dev->dig_H1, 1) && - read_register16(i2c_addr, 0xe1, (uint16_t *)&dev->dig_H2) && - i2c_slave_read(i2c_addr, 0xe3, &dev->dig_H3, 1) && - read_register16(i2c_addr, 0xe4, &h4) && - read_register16(i2c_addr, 0xe5, &h5) && - i2c_slave_read(i2c_addr, 0xe7, (uint8_t *)&dev->dig_H6, 1)) { + if (!read_data(&dev->i2c_dev, 0xa1, &dev->dig_H1, 1) && + read_register16(&dev->i2c_dev, 0xe1, (uint16_t *)&dev->dig_H2) && + !read_data(&dev->i2c_dev, 0xe3, &dev->dig_H3, 1) && + read_register16(&dev->i2c_dev, 0xe4, &h4) && + read_register16(&dev->i2c_dev, 0xe5, &h5) && + !read_data(&dev->i2c_dev, 0xe7, (uint8_t *)&dev->dig_H6, 1)) { dev->dig_H4 = (h4 & 0x00ff) << 4 | (h4 & 0x0f00) >> 8; dev->dig_H5 = h5 >> 4; debug("Calibration data received:"); @@ -139,23 +141,20 @@ static bool read_hum_calibration_data(bmp280_t *dev) return false; } -static bool write_register8(uint8_t i2c_addr, uint8_t addr, uint8_t value) +static int write_register8(i2c_dev_t* dev, uint8_t addr, uint8_t value) { - uint8_t d[] = {addr, value}; - - return i2c_slave_write(i2c_addr, d, 2); + return i2c_slave_write(dev->bus, dev->addr, &addr, &value, 1); } bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) { - uint8_t i2c_addr = dev->i2c_addr; - if (i2c_addr != BMP280_I2C_ADDRESS_0 && i2c_addr != BMP280_I2C_ADDRESS_1) { + if (dev->i2c_dev.addr != BMP280_I2C_ADDRESS_0 && dev->i2c_dev.addr != BMP280_I2C_ADDRESS_1) { debug("Invalid I2C address"); return false; } - if (!i2c_slave_read(i2c_addr, BMP280_REG_ID, &dev->id, 1)) { + if (read_data(&dev->i2c_dev, BMP280_REG_ID, &dev->id, 1)) { debug("Sensor not found"); return false; } @@ -166,7 +165,7 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) } // Soft reset. - if (!write_register8(i2c_addr, BMP280_REG_RESET, BMP280_RESET_VALUE)) { + if (write_register8(&dev->i2c_dev, BMP280_REG_RESET, BMP280_RESET_VALUE)) { debug("Failed resetting sensor"); return false; } @@ -174,7 +173,7 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) // Wait until finished copying over the NVP data. while (1) { uint8_t status; - if (i2c_slave_read(i2c_addr, BMP280_REG_STATUS, &status, 1) && (status & 1) == 0) + if (!read_data(&dev->i2c_dev, BMP280_REG_STATUS, &status, 1) && (status & 1) == 0) break; } @@ -190,7 +189,7 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) uint8_t config = (params->standby << 5) | (params->filter << 2); debug("Writing config reg=%x", config); - if (!write_register8(i2c_addr, BMP280_REG_CONFIG, config)) { + if (write_register8(&dev->i2c_dev, BMP280_REG_CONFIG, config)) { debug("Failed configuring sensor"); return false; } @@ -207,14 +206,14 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) // Write crtl hum reg first, only active after write to BMP280_REG_CTRL. uint8_t ctrl_hum = params->oversampling_humidity; debug("Writing ctrl hum reg=%x", ctrl_hum); - if (!write_register8(i2c_addr, BMP280_REG_CTRL_HUM, ctrl_hum)) { + if (write_register8(&dev->i2c_dev, BMP280_REG_CTRL_HUM, ctrl_hum)) { debug("Failed controlling sensor"); return false; } } debug("Writing ctrl reg=%x", ctrl); - if (!write_register8(i2c_addr, BMP280_REG_CTRL, ctrl)) { + if (write_register8(&dev->i2c_dev, BMP280_REG_CTRL, ctrl)) { debug("Failed controlling sensor"); return false; } @@ -225,12 +224,12 @@ bool bmp280_init(bmp280_t *dev, bmp280_params_t *params) bool bmp280_force_measurement(bmp280_t *dev) { uint8_t ctrl; - if (!i2c_slave_read(dev->i2c_addr, BMP280_REG_CTRL, &ctrl, 1)) + if (read_data(&dev->i2c_dev, BMP280_REG_CTRL, &ctrl, 1)) return false; ctrl &= ~0b11; // clear two lower bits ctrl |= BMP280_MODE_FORCED; debug("Writing ctrl reg=%x", ctrl); - if (!write_register8(dev->i2c_addr, BMP280_REG_CTRL, ctrl)) { + if (write_register8(&dev->i2c_dev, BMP280_REG_CTRL, ctrl)) { debug("Failed starting forced mode"); return false; } @@ -240,7 +239,7 @@ bool bmp280_force_measurement(bmp280_t *dev) bool bmp280_is_measuring(bmp280_t *dev) { uint8_t status; - if (!i2c_slave_read(dev->i2c_addr, BMP280_REG_STATUS, &status, 1)) + if (read_data(&dev->i2c_dev, BMP280_REG_STATUS, &status, 1)) return false; if (status & (1 << 3)) { debug("Status: measuring"); @@ -342,7 +341,7 @@ bool bmp280_read_fixed(bmp280_t *dev, int32_t *temperature, // Need to read in one sequence to ensure they match. size_t size = humidity ? 8 : 6; - if (!i2c_slave_read(dev->i2c_addr, 0xf7, data, size)) { + if (read_data(&dev->i2c_dev, 0xf7, data, size)) { debug("Failed reading"); return false; } diff --git a/extras/bmp280/bmp280.h b/extras/bmp280/bmp280.h index 4646d25..39805fc 100644 --- a/extras/bmp280/bmp280.h +++ b/extras/bmp280/bmp280.h @@ -26,6 +26,7 @@ #include #include +#include "i2c/i2c.h" #ifdef __cplusplus extern "C" { @@ -127,7 +128,7 @@ typedef struct { int16_t dig_H5; int8_t dig_H6; - uint8_t i2c_addr; /* I2C address. */ + i2c_dev_t i2c_dev; /* I2C dev setting. */ uint8_t id; /* Chip ID */ } bmp280_t; diff --git a/extras/dhcpserver/dhcpserver.c b/extras/dhcpserver/dhcpserver.c index d87daab..934beb2 100644 --- a/extras/dhcpserver/dhcpserver.c +++ b/extras/dhcpserver/dhcpserver.c @@ -14,18 +14,22 @@ * BSD Licensed as described in the file LICENSE */ #include +#include #include #include #include #include +#include "esplibs/libmain.h" /* 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 full-sized clients send us more than this. */ #define DHCP_OPTIONS_LEN 312 -#include +#include +#include +#include _Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 312, "dhcp_msg_t should have extended options size"); @@ -35,15 +39,20 @@ _Static_assert(sizeof(struct dhcp_msg) == offsetof(struct dhcp_msg, options) + 3 typedef struct { uint8_t hwaddr[NETIF_MAX_HWADDR_LEN]; + uint8_t active; uint32_t expires; } dhcp_lease_t; typedef struct { struct netconn *nc; uint8_t max_leases; - ip_addr_t first_client_addr; + ip4_addr_t first_client_addr; struct netif *server_if; dhcp_lease_t *leases; /* length max_leases */ + /* Optional router */ + ip4_addr_t router; + /* Optional DNS server */ + ip4_addr_t dns; } server_state_t; /* Only one DHCP server task can run at once, so we have global state @@ -68,51 +77,67 @@ 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); /* 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"); else sprintf(dest, "%d.%d.%d.%d", ip4_addr1(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 */ - if(dhcpserver_task_handle) + if (dhcpserver_task_handle) dhcpserver_stop(); state = malloc(sizeof(server_state_t)); state->max_leases = max_leases; 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() - 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) { - if(dhcpserver_task_handle) { + if (dhcpserver_task_handle) { vTaskDelete(dhcpserver_task_handle); free(state); 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) { /* netif_list isn't assigned until after user_init completes, which is why we do it inside the task */ state->server_if = netif_list; /* TODO: Make this configurable */ state->nc = netconn_new (NETCONN_UDP); - if(!state->nc) { + if (!state->nc) { printf("DHCP Server Error: Failed to allocate socket.\r\n"); 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) { @@ -121,29 +146,32 @@ static void dhcpserver_task(void *pxParameter) /* Receive a DHCP packet */ 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); continue; } /* expire any leases that have passed */ uint32_t now = xTaskGetTickCount(); - for(int i = 0; i < state->max_leases; i++) { - uint32_t expires = state->leases[i].expires; - if(expires && expires < now) - state->leases[i].expires = 0; + for (int i = 0; i < state->max_leases; i++) { + if (state->leases[i].active) { + uint32_t expires = state->leases[i].expires - now; + if (expires >= 0x80000000) { + state->leases[i].active = 0; + } + } } ip_addr_t received_ip; u16_t 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 */ netbuf_delete(netbuf); 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)); } @@ -152,18 +180,18 @@ static void dhcpserver_task(void *pxParameter) uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN, NULL); - if(!message_type) { + if (!message_type) { printf("DHCP Server Error: No message type field found"); continue; } - printf("State dump. Message type %d\n", *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]; - printf("lease slot %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, lease->expires, lease->hwaddr[0], - lease->hwaddr[1], lease->hwaddr[2], lease->hwaddr[3], lease->hwaddr[4], - lease->hwaddr[5]); + printf("lease slot %d active %d expiry %d hwaddr %02x:%02x:%02x:%02x:%02x:%02x\r\n", i, + lease->active, lease->expires - now, + lease->hwaddr[0], lease->hwaddr[1], lease->hwaddr[2], + lease->hwaddr[3], lease->hwaddr[4], lease->hwaddr[5]); } switch(*message_type) { @@ -184,13 +212,13 @@ static void dhcpserver_task(void *pxParameter) static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg) { - if(dhcpmsg->htype != DHCP_HTYPE_ETH) + if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET) return; - if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) + if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) return; dhcp_lease_t *freelease = find_lease_slot(dhcpmsg->chaddr); - if(!freelease) { + if (!freelease) { printf("DHCP Server: All leases taken.\r\n"); return; /* Nothing available, so do nothing */ } @@ -199,13 +227,19 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg) dhcpmsg->op = DHCP_BOOTREPLY; bzero(dhcpmsg->options, DHCP_OPTIONS_LEN); - ip_addr_copy(dhcpmsg->yiaddr, state->first_client_addr); - ip4_addr4(&(dhcpmsg->yiaddr)) += (freelease - state->leases); + dhcpmsg->yiaddr.addr = lwip_htonl(lwip_ntohl(state->first_client_addr.addr) + (freelease - state->leases)); uint8_t *opt = (uint8_t *)&dhcpmsg->options; 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_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); struct netbuf *netbuf = netbuf_new(); @@ -218,17 +252,17 @@ static void handle_dhcp_discover(struct dhcp_msg *dhcpmsg) static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) { static char ipbuf[16]; - if(dhcpmsg->htype != DHCP_HTYPE_ETH) + if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET) return; - if(dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) + if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) 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); - if(requested_ip_opt) { - memcpy(&requested_ip.addr, requested_ip_opt, 4); - } else if(ip_addr_cmp(&requested_ip, IP_ADDR_ANY)) { - ip_addr_copy(requested_ip, dhcpmsg->ciaddr); + if (requested_ip_opt) { + memcpy(&requested_ip.addr, requested_ip_opt, 4); + } else if (ip4_addr_cmp(&requested_ip, IP4_ADDR_ANY4)) { + ip4_addr_copy(requested_ip, dhcpmsg->ciaddr); } else { printf("DHCP Server Error: No requested IP\r\n"); send_dhcp_nak(dhcpmsg); @@ -236,7 +270,7 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) } /* 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_addr3(&requested_ip) != ip4_addr3(&state->first_client_addr)) { sprintf_ipaddr(&requested_ip, ipbuf); @@ -246,14 +280,14 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) } /* Test the last octet is in the MAXCLIENTS range */ 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"); send_dhcp_nak(dhcpmsg); return; } 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"); send_dhcp_nak(dhcpmsg); @@ -265,13 +299,17 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) printf("DHCP lease addr %s assigned to MAC %02x:%02x:%02x:%02x:%02x:%02x\r\n", ipbuf, requested_lease->hwaddr[0], requested_lease->hwaddr[1], requested_lease->hwaddr[2], requested_lease->hwaddr[3], requested_lease->hwaddr[4], 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 */ dhcpmsg->op = DHCP_BOOTREPLY; 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; opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_ACK); @@ -279,6 +317,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_SERVER_ID, &state->server_if->ip_addr, 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); struct netbuf *netbuf = netbuf_new(); @@ -291,7 +336,8 @@ static void handle_dhcp_request(struct dhcp_msg *dhcpmsg) static void handle_dhcp_release(struct dhcp_msg *dhcpmsg) { dhcp_lease_t *lease = find_lease_slot(dhcpmsg->chaddr); - if(lease) { + if (lease) { + lease->active = 0; lease->expires = 0; } } @@ -319,17 +365,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 *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 len = *p++; - if(type == DHCP_OPTION_END) + if (type == DHCP_OPTION_END) 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 */ - if(type == option_num) { - if(len < min_length) + if (type == option_num) { + if (len < min_length) break; - if(length) + if (length) *length = len; return p; /* start of actual option data */ } @@ -349,7 +395,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) { *opt++ = type; - if(len) { + if (len) { *opt++ = len; memcpy(opt, value, len); } @@ -360,8 +406,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) { dhcp_lease_t *empty_lease = NULL; - for(int i = 0; i < state->max_leases; i++) { - if(state->leases[i].expires == 0 && !empty_lease) + for (int i = 0; i < state->max_leases; i++) { + if (!state->leases[i].active && !empty_lease) empty_lease = &state->leases[i]; else if (memcmp(hwaddr, state->leases[i].hwaddr, 6) == 0) return &state->leases[i]; diff --git a/extras/dhcpserver/include/dhcpserver.h b/extras/dhcpserver/include/dhcpserver.h index 95a59b8..62fa0ac 100644 --- a/extras/dhcpserver/include/dhcpserver.h +++ b/extras/dhcpserver/include/dhcpserver.h @@ -26,14 +26,20 @@ extern "C" { to a client. Subsequent lease addresses are calculated by 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. */ 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 } #endif diff --git a/extras/ds1307/ds1307.c b/extras/ds1307/ds1307.c index e5306a8..7cee34a 100644 --- a/extras/ds1307/ds1307.c +++ b/extras/ds1307/ds1307.c @@ -6,10 +6,8 @@ * BSD Licensed as described in the file LICENSE */ #include "ds1307.h" -#include #include -#define ADDR 0x68 #define RAM_SIZE 56 #define TIME_REG 0 @@ -40,38 +38,36 @@ static uint8_t dec2bcd(uint8_t val) return ((val / 10) << 4) + (val % 10); } -static uint8_t read_register(uint8_t reg) +static uint8_t read_register(i2c_dev_t* dev, uint8_t reg) { uint8_t val; - i2c_slave_read(ADDR, reg, &val, 1); + i2c_slave_read(dev->bus, dev->addr, ®, &val, 1); return val; } -static void update_register(uint8_t reg, uint8_t mask, uint8_t val) +static void update_register(i2c_dev_t* dev, uint8_t reg, uint8_t mask, uint8_t val) { - uint8_t buf[2]; + uint8_t buf = (read_register(dev,reg) & mask) | val; - buf[0] = reg; - buf[1] = (read_register(reg) & mask) | val; - - i2c_slave_write(ADDR, buf, 2); + i2c_slave_write(dev->bus, dev->addr, ®, &buf, 1); } -void ds1307_start(bool start) +void ds1307_start(i2c_dev_t* dev, bool start) { - update_register(TIME_REG, CH_MASK, start ? 0 : CH_BIT); + update_register(dev, TIME_REG, CH_MASK, start ? 0 : CH_BIT); } -bool ds1307_is_running() +bool ds1307_is_running(i2c_dev_t* dev) { - return !(read_register(TIME_REG) & CH_BIT); + return !(read_register(dev, TIME_REG) & CH_BIT); } -void ds1307_get_time(struct tm *time) +void ds1307_get_time(i2c_dev_t* dev, struct tm *time) { uint8_t buf[7]; + uint8_t reg = TIME_REG ; - i2c_slave_read(ADDR, TIME_REG, buf, 7); + i2c_slave_read(dev->bus, dev->addr, ® , buf, 7); time->tm_sec = bcd2dec(buf[0] & SECONDS_MASK); time->tm_min = bcd2dec(buf[1]); @@ -89,7 +85,7 @@ void ds1307_get_time(struct tm *time) time->tm_year = bcd2dec(buf[6]) + 2000; } -void ds1307_set_time(const struct tm *time) +void ds1307_set_time(i2c_dev_t* dev, const struct tm *time) { uint8_t buf[8]; buf[0] = TIME_REG; @@ -101,64 +97,51 @@ void ds1307_set_time(const struct tm *time) buf[6] = dec2bcd(time->tm_mon + 1); buf[7] = dec2bcd(time->tm_year - 2000); - i2c_slave_write(ADDR, buf, 8); + i2c_slave_write(dev->bus, dev->addr, &buf[0], &buf[1] , 7); } -void ds1307_enable_squarewave(bool enable) +void ds1307_enable_squarewave(i2c_dev_t* dev, bool enable) { - update_register(CONTROL_REG, SQWE_MASK, enable ? SQWE_BIT : 0); + update_register(dev, CONTROL_REG, SQWE_MASK, enable ? SQWE_BIT : 0); } -bool ds1307_is_squarewave_enabled() +bool ds1307_is_squarewave_enabled(i2c_dev_t* dev) { - return read_register(CONTROL_REG) & SQWE_BIT; + return read_register(dev, CONTROL_REG) & SQWE_BIT; } -void ds1307_set_squarewave_freq(ds1307_squarewave_freq_t freq) +void ds1307_set_squarewave_freq(i2c_dev_t* dev, ds1307_squarewave_freq_t freq) { - update_register(CONTROL_REG, SQWEF_MASK, (uint8_t)freq); + update_register(dev, CONTROL_REG, SQWEF_MASK, (uint8_t)freq); } -ds1307_squarewave_freq_t ds1307_get_squarewave_freq() +ds1307_squarewave_freq_t ds1307_get_squarewave_freq(i2c_dev_t* dev) { - return (ds1307_squarewave_freq_t)(read_register(CONTROL_REG) & SQWEF_MASK); + return (ds1307_squarewave_freq_t)(read_register(dev, CONTROL_REG) & SQWEF_MASK); } -bool ds1307_get_output() +bool ds1307_get_output(i2c_dev_t* dev) { - return read_register(CONTROL_REG) & OUT_BIT; + return read_register(dev, CONTROL_REG) & OUT_BIT; } -void ds1307_set_output(bool value) +void ds1307_set_output(i2c_dev_t* dev, bool value) { - update_register(CONTROL_REG, OUT_MASK, value ? OUT_BIT : 0); + update_register(dev, CONTROL_REG, OUT_MASK, value ? OUT_BIT : 0); } -bool ds1307_read_ram(uint8_t offset, uint8_t *buf, uint8_t len) +int ds1307_read_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len) { if (offset + len > RAM_SIZE) return false; + uint8_t reg = RAM_REG + offset ; - return i2c_slave_read(ADDR, RAM_REG + offset, buf, len); + return i2c_slave_read(dev->bus, dev->addr, ®, buf, len); } -bool ds1307_write_ram(uint8_t offset, uint8_t *buf, uint8_t len) +int ds1307_write_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len) { if (offset + len > RAM_SIZE) return false; + uint8_t reg = RAM_REG + offset ; - // temporary buffer on the stack is not good so copy-paste :( - bool success = false; - do { - i2c_start(); - if (!i2c_write(ADDR << 1)) - break; - if (!i2c_write(RAM_REG + offset)) - break; - while (len--) { - if (!i2c_write(*buf++)) - break; - } - i2c_stop(); - success = true; - } while(0); - return success; + return i2c_slave_write(dev->bus, dev->addr, ®, buf, len); } diff --git a/extras/ds1307/ds1307.h b/extras/ds1307/ds1307.h index d2daeee..9baa904 100644 --- a/extras/ds1307/ds1307.h +++ b/extras/ds1307/ds1307.h @@ -11,11 +11,13 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif +#define DS1307_ADDR 0x68 /** * Squarewave frequency */ @@ -31,80 +33,80 @@ typedef enum _ds1307_squarewave_freq_t * \brief Start/stop clock * \param start Start clock if true */ -void ds1307_start(bool start); +void ds1307_start(i2c_dev_t* dev, bool start); /** * \brief Get current clock state * \return true if clock running */ -bool ds1307_is_running(); +bool ds1307_is_running(i2c_dev_t* dev); /** * \brief Get current time * \param time Pointer to the time struct to fill */ -void ds1307_get_time(struct tm *time); +void ds1307_get_time(i2c_dev_t* dev, struct tm *time); /** * \brief Set time to RTC * \param time Pointer to the time struct */ -void ds1307_set_time(const struct tm *time); +void ds1307_set_time(i2c_dev_t* dev, const struct tm *time); /** * \brief Enable or disable square-wave oscillator output * \param enable Enable oscillator if true */ -void ds1307_enable_squarewave(bool enable); +void ds1307_enable_squarewave(i2c_dev_t* dev, bool enable); /** * \brief Get square-wave oscillator output * \return true if square-wave oscillator enabled */ -bool ds1307_is_squarewave_enabled(); +bool ds1307_is_squarewave_enabled(i2c_dev_t* dev); /** * \brief Set square-wave oscillator frequency * \param freq Frequency */ -void ds1307_set_squarewave_freq(ds1307_squarewave_freq_t freq); +void ds1307_set_squarewave_freq(i2c_dev_t* dev, ds1307_squarewave_freq_t freq); /** * \brief Get current square-wave oscillator frequency * \return Frequency */ -ds1307_squarewave_freq_t ds1307_get_squarewave_freq(); +ds1307_squarewave_freq_t ds1307_get_squarewave_freq(i2c_dev_t* dev); /** * \brief Get current output level of the SQW/OUT pin * \return true if high */ -bool ds1307_get_output(); +bool ds1307_get_output(i2c_dev_t* dev); /** * \brief Set output level of the SQW/OUT pin * Set output level if square-wave output is disabled * \param value High level if true */ -void ds1307_set_output(bool value); +void ds1307_set_output(i2c_dev_t* dev, bool value); /** * \brief Read RAM contents into the buffer * \param offset Start byte, 0..55 * \param buf Buffer * \param len Bytes to read, 1..56 - * \return false if error occured + * \return Non-zero if error occured */ -bool ds1307_read_ram(uint8_t offset, uint8_t *buf, uint8_t len); +int ds1307_read_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len); /** * \brief Write buffer to RTC RAM * \param offset Start byte, 0..55 * \param buf Buffer * \param len Bytes to write, 1..56 - * \return false if error occured + * \return Non-zero if error occured */ -bool ds1307_write_ram(uint8_t offset, uint8_t *buf, uint8_t len); +int ds1307_write_ram(i2c_dev_t* dev, uint8_t offset, uint8_t *buf, uint8_t len); #ifdef __cplusplus diff --git a/extras/ds3231/ds3231.c b/extras/ds3231/ds3231.c index 543474e..4b0e65c 100644 --- a/extras/ds3231/ds3231.c +++ b/extras/ds3231/ds3231.c @@ -11,64 +11,61 @@ #include "espressif/sdk_private.h" #include "esp8266.h" -#include "i2c/i2c.h" /* Convert normal decimal to binary coded decimal */ 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 */ 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 * returns true to indicate success */ -static inline bool ds3231_send(uint8_t *data, uint8_t len) +static inline int ds3231_send(i2c_dev_t *dev, uint8_t reg, uint8_t *data, uint8_t len) { - return i2c_slave_write(DS3231_ADDR, data, len); + return i2c_slave_write(dev->bus, dev->addr, ®, data, len); } /* Read a number of bytes from the rtc over i2c * returns true to indicate success */ -static inline bool ds3231_recv(uint8_t *data, uint8_t len) +static inline int ds3231_recv(i2c_dev_t *dev, uint8_t reg, uint8_t *data, uint8_t len) { - return i2c_slave_read(DS3231_ADDR, data[0], data, len); + return i2c_slave_read(dev->bus, dev->addr, ®, data, len); } -bool ds3231_setTime(struct tm *time) +int ds3231_setTime(i2c_dev_t *dev, struct tm *time) { - uint8_t data[8]; + uint8_t data[7]; - /* start register */ - data[0] = DS3231_ADDR_TIME; /* time/date data */ - data[1] = decToBcd(time->tm_sec); - data[2] = decToBcd(time->tm_min); - data[3] = decToBcd(time->tm_hour); - data[4] = decToBcd(time->tm_wday + 1); - data[5] = decToBcd(time->tm_mday); - data[6] = decToBcd(time->tm_mon + 1); - data[7] = decToBcd(time->tm_year - 100); + data[0] = decToBcd(time->tm_sec); + data[1] = decToBcd(time->tm_min); + 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[4] = decToBcd(time->tm_mday); + data[5] = decToBcd(time->tm_mon + 1); + data[6] = decToBcd(time->tm_year - 100); - return ds3231_send(data, 8); + return ds3231_send(dev, DS3231_ADDR_TIME, data, 7); } -bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2) +int ds3231_setAlarm(i2c_dev_t *dev, uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2) { int i = 0; - uint8_t data[8]; - - /* start register */ - data[i++] = (alarms == DS3231_ALARM_2 ? DS3231_ADDR_ALARM2 : DS3231_ADDR_ALARM1); + uint8_t data[7]; /* alarm 1 data */ - if (alarms != DS3231_ALARM_2) { + if (alarms != DS3231_ALARM_2) + { data[i++] = (option1 >= DS3231_ALARM1_MATCH_SEC ? decToBcd(time1->tm_sec) : DS3231_ALARM_NOTSET); data[i++] = (option1 >= DS3231_ALARM1_MATCH_SECMIN ? decToBcd(time1->tm_min) : DS3231_ALARM_NOTSET); data[i++] = (option1 >= DS3231_ALARM1_MATCH_SECMINHOUR ? decToBcd(time1->tm_hour) : DS3231_ALARM_NOTSET); @@ -77,14 +74,15 @@ bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct t } /* alarm 2 data */ - if (alarms != DS3231_ALARM_1) { + if (alarms != DS3231_ALARM_1) + { data[i++] = (option2 >= DS3231_ALARM2_MATCH_MIN ? decToBcd(time2->tm_min) : DS3231_ALARM_NOTSET); data[i++] = (option2 >= DS3231_ALARM2_MATCH_MINHOUR ? decToBcd(time2->tm_hour) : DS3231_ALARM_NOTSET); data[i++] = (option2 == DS3231_ALARM2_MATCH_MINHOURDAY ? (decToBcd(time2->tm_wday + 1) & DS3231_ALARM_WDAY) : (option2 == DS3231_ALARM2_MATCH_MINHOURDATE ? decToBcd(time2->tm_mday) : DS3231_ALARM_NOTSET)); } - return ds3231_send(data, i); + return ds3231_send(dev, (alarms == DS3231_ALARM_2 ? DS3231_ADDR_ALARM2 : DS3231_ADDR_ALARM1), data, i); } /* Get a byte containing just the requested bits @@ -94,15 +92,15 @@ bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct t * of use a mask of 0xff to just return the whole register byte * returns true to indicate success */ -bool ds3231_getFlag(uint8_t addr, uint8_t mask, uint8_t *flag) +bool ds3231_getFlag(i2c_dev_t *dev, uint8_t addr, uint8_t mask, uint8_t *flag) { - uint8_t data[1]; + uint8_t data; /* get register */ - data[0] = addr; - if (ds3231_send(data, 1) && ds3231_recv(data, 1)) { + if (!ds3231_recv(dev, addr, &data, 1)) + { /* return only requested flag */ - *flag = (data[0] & mask); + *flag = (data & mask); return true; } @@ -115,34 +113,34 @@ bool ds3231_getFlag(uint8_t addr, uint8_t mask, uint8_t *flag) * DS3231_SET/DS3231_CLEAR/DS3231_REPLACE * returns true to indicate success */ -bool ds3231_setFlag(uint8_t addr, uint8_t bits, uint8_t mode) +bool ds3231_setFlag(i2c_dev_t *dev, uint8_t addr, uint8_t bits, uint8_t mode) { - uint8_t data[2]; + uint8_t data; - data[0] = addr; /* get status register */ - if (ds3231_send(data, 1) && ds3231_recv(data+1, 1)) { + if (!ds3231_recv(dev, addr, &data, 1)) + { /* clear the flag */ if (mode == DS3231_REPLACE) - data[1] = bits; + data = bits; else if (mode == DS3231_SET) - data[1] |= bits; + data |= bits; else - data[1] &= ~bits; + data &= ~bits; - if (ds3231_send(data, 2)) { + if (!ds3231_send(dev, addr, &data, 1)) return true; - } } return false; } -bool ds3231_getOscillatorStopFlag(bool *flag) +bool ds3231_getOscillatorStopFlag(i2c_dev_t *dev, bool *flag) { uint8_t f; - if (ds3231_getFlag(DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, &f)) { + if (ds3231_getFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, &f)) + { *flag = (f ? true : false); return true; } @@ -150,75 +148,77 @@ bool ds3231_getOscillatorStopFlag(bool *flag) return false; } -inline bool ds3231_clearOscillatorStopFlag() +inline bool ds3231_clearOscillatorStopFlag(i2c_dev_t *dev) { - return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, DS3231_CLEAR); + return ds3231_setFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_OSCILLATOR, DS3231_CLEAR); } -inline bool ds3231_getAlarmFlags(uint8_t *alarms) +inline bool ds3231_getAlarmFlags(i2c_dev_t *dev, uint8_t *alarms) { - return ds3231_getFlag(DS3231_ADDR_STATUS, DS3231_ALARM_BOTH, alarms); + return ds3231_getFlag(dev, DS3231_ADDR_STATUS, DS3231_ALARM_BOTH, alarms); } -inline bool ds3231_clearAlarmFlags(uint8_t alarms) +inline bool ds3231_clearAlarmFlags(i2c_dev_t *dev, uint8_t alarms) { - return ds3231_setFlag(DS3231_ADDR_STATUS, alarms, DS3231_CLEAR); + return ds3231_setFlag(dev, DS3231_ADDR_STATUS, alarms, DS3231_CLEAR); } -inline bool ds3231_enableAlarmInts(uint8_t alarms) +inline bool ds3231_enableAlarmInts(i2c_dev_t *dev, uint8_t alarms) { - return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS | alarms, DS3231_SET); + return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS | alarms, DS3231_SET); } -inline bool ds3231_disableAlarmInts(uint8_t alarms) +inline bool ds3231_disableAlarmInts(i2c_dev_t *dev, uint8_t alarms) { /* Just disable specific alarm(s) requested * does not disable alarm interrupts generally (which would enable the squarewave) */ - return ds3231_setFlag(DS3231_ADDR_CONTROL, alarms, DS3231_CLEAR); + return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, alarms, DS3231_CLEAR); } -inline bool ds3231_enable32khz() +inline bool ds3231_enable32khz(i2c_dev_t *dev) { - return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_SET); + return ds3231_setFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_SET); } -inline bool ds3231_disable32khz() +inline bool ds3231_disable32khz(i2c_dev_t *dev) { - return ds3231_setFlag(DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_CLEAR); + return ds3231_setFlag(dev, DS3231_ADDR_STATUS, DS3231_STAT_32KHZ, DS3231_CLEAR); } -inline bool ds3231_enableSquarewave() +inline bool ds3231_enableSquarewave(i2c_dev_t *dev) { - return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_CLEAR); + return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_CLEAR); } -inline bool ds3231_disableSquarewave() +inline bool ds3231_disableSquarewave(i2c_dev_t *dev) { - return ds3231_setFlag(DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_SET); + return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, DS3231_CTRL_ALARM_INTS, DS3231_SET); } -bool ds3231_setSquarewaveFreq(uint8_t freq) +bool ds3231_setSquarewaveFreq(i2c_dev_t *dev, uint8_t freq) { uint8_t flag = 0; - if (ds3231_getFlag(DS3231_ADDR_CONTROL, 0xff, &flag)) { + if (ds3231_getFlag(dev, DS3231_ADDR_CONTROL, 0xff, &flag)) + { /* clear current rate */ flag &= ~DS3231_CTRL_SQWAVE_8192HZ; /* set new rate */ flag |= freq; - return ds3231_setFlag(DS3231_ADDR_CONTROL, flag, DS3231_REPLACE); + return ds3231_setFlag(dev, DS3231_ADDR_CONTROL, flag, DS3231_REPLACE); } return false; } -bool ds3231_getRawTemp(int16_t *temp) +bool ds3231_getRawTemp(i2c_dev_t *dev, int16_t *temp) { uint8_t data[2]; data[0] = DS3231_ADDR_TEMP; - if (ds3231_send(data, 1) && ds3231_recv(data, 2)) { + if (!ds3231_recv(dev, DS3231_ADDR_TEMP,data, 2)) + { *temp = (int16_t)(int8_t)data[0] << 2 | data[1] >> 6; return true; } @@ -226,11 +226,11 @@ bool ds3231_getRawTemp(int16_t *temp) return false; } -bool ds3231_getTempInteger(int8_t *temp) +bool ds3231_getTempInteger(i2c_dev_t *dev, int8_t *temp) { int16_t tInt; - if (ds3231_getRawTemp(&tInt)) { + if (ds3231_getRawTemp(dev, &tInt)) { *temp = tInt >> 2; return true; } @@ -238,11 +238,11 @@ bool ds3231_getTempInteger(int8_t *temp) return false; } -bool ds3231_getTempFloat(float *temp) +bool ds3231_getTempFloat(i2c_dev_t *dev, float *temp) { int16_t tInt; - if (ds3231_getRawTemp(&tInt)) { + if (ds3231_getRawTemp(dev, &tInt)) { *temp = tInt * 0.25; return true; } @@ -250,18 +250,13 @@ bool ds3231_getTempFloat(float *temp) return false; } -bool ds3231_getTime(struct tm *time) +bool ds3231_getTime(i2c_dev_t *dev, struct tm *time) { uint8_t data[7]; - /* start register address */ - data[0] = DS3231_ADDR_TIME; - if (!ds3231_send(data, 1)) { - return false; - } - /* read time */ - if (!ds3231_recv(data, 7)) { + if (ds3231_recv(dev, DS3231_ADDR_TIME, data, 7)) + { return false; } @@ -287,10 +282,5 @@ bool ds3231_getTime(struct tm *time) //applyTZ(time); return true; - -} -void ds3231_Init(uint8_t scl, uint8_t sda) -{ - i2c_init(scl, sda); } diff --git a/extras/ds3231/ds3231.h b/extras/ds3231/ds3231.h index ccc7335..6ef9ff7 100644 --- a/extras/ds3231/ds3231.h +++ b/extras/ds3231/ds3231.h @@ -12,6 +12,8 @@ #include #include #include +#include "i2c/i2c.h" + #ifdef __cplusplus extern "C" { @@ -87,7 +89,7 @@ enum { * I suggest using GMT and applying timezone and DST when read back * returns true to indicate success */ -bool ds3231_setTime(struct tm *time); +int ds3231_setTime(i2c_dev_t *dev, struct tm *time); /* Set alarms * alarm1 works with seconds, minutes, hours and day of week/month, or fires every second @@ -100,30 +102,30 @@ bool ds3231_setTime(struct tm *time); * if you want to enable interrupts for the alarms you need to do that separately * returns true to indicate success */ -bool ds3231_setAlarm(uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2); +int ds3231_setAlarm(i2c_dev_t *dev, uint8_t alarms, struct tm *time1, uint8_t option1, struct tm *time2, uint8_t option2); /* Check if oscillator has previously stopped, e.g. no power/battery or disabled * sets flag to true if there has been a stop * returns true to indicate success */ -bool ds3231_getOscillatorStopFlag(bool *flag); +bool ds3231_getOscillatorStopFlag(i2c_dev_t *dev, bool *flag); /* Clear the oscillator stopped flag * returns true to indicate success */ -bool ds3231_clearOscillatorStopFlag(); +bool ds3231_clearOscillatorStopFlag(i2c_dev_t *dev); /* Check which alarm(s) have past * sets alarms to DS3231_ALARM_NONE/DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH * returns true to indicate success */ -bool ds3231_getAlarmFlags(uint8_t *alarms); +bool ds3231_getAlarmFlags(i2c_dev_t *dev, uint8_t *alarms); /* Clear alarm past flag(s) * pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH * returns true to indicate success */ -bool ds3231_clearAlarmFlags(uint8_t alarm); +bool ds3231_clearAlarmFlags(i2c_dev_t *dev, uint8_t alarm); /* enable alarm interrupts (and disables squarewave) * pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH @@ -132,61 +134,60 @@ bool ds3231_clearAlarmFlags(uint8_t alarm); * interrupt enabled, else it will trigger immediately * returns true to indicate success */ -bool ds3231_enableAlarmInts(uint8_t alarms); +bool ds3231_enableAlarmInts(i2c_dev_t *dev, uint8_t alarms); /* Disable alarm interrupts (does not (re-)enable squarewave) * pass DS3231_ALARM_1/DS3231_ALARM_2/DS3231_ALARM_BOTH * returns true to indicate success */ -bool ds3231_disableAlarmInts(uint8_t alarms); +bool ds3231_disableAlarmInts(i2c_dev_t *dev, uint8_t alarms); /* Enable the output of 32khz signal * returns true to indicate success */ -bool ds3231_enable32khz(); +bool ds3231_enable32khz(i2c_dev_t *dev); /* Disable the output of 32khz signal * returns true to indicate success */ -bool ds3231_disable32khz(); +bool ds3231_disable32khz(i2c_dev_t *dev); /* Enable the squarewave output (disables alarm interrupt functionality) * returns true to indicate success */ -bool ds3231_enableSquarewave(); +bool ds3231_enableSquarewave(i2c_dev_t *dev); /* Disable the squarewave output (which re-enables alarm interrupts, but individual * alarm interrupts also need to be enabled, if not already, before they will trigger) * returns true to indicate success */ -bool ds3231_disableSquarewave(); +bool ds3231_disableSquarewave(i2c_dev_t *dev); /* Set the frequency of the squarewave output (but does not enable it) * pass DS3231_SQUAREWAVE_RATE_1HZ/DS3231_SQUAREWAVE_RATE_1024HZ/DS3231_SQUAREWAVE_RATE_4096HZ/DS3231_SQUAREWAVE_RATE_8192HZ * returns true to indicate success */ -bool ds3231_setSquarewaveFreq(uint8_t freq); +bool ds3231_setSquarewaveFreq(i2c_dev_t *dev, uint8_t freq); /* Get the raw value * returns true to indicate success */ -bool ds3231_getRawTemp(int16_t *temp); +bool ds3231_getRawTemp(i2c_dev_t *dev, int16_t *temp); /* Get the temperature as an integer * returns true to indicate success */ -bool ds3231_getTempInteger(int8_t *temp); +bool ds3231_getTempInteger(i2c_dev_t *dev, int8_t *temp); /* Get the temerapture as a float (in quarter degree increments) * returns true to indicate success */ -bool ds3231_getTempFloat(float *temp); +bool ds3231_getTempFloat(i2c_dev_t *dev, float *temp); /* Get the time from the rtc, populates a supplied tm struct * returns true to indicate success */ -bool ds3231_getTime(struct tm *time); -void ds3231_Init(uint8_t scl, uint8_t sda); +bool ds3231_getTime(i2c_dev_t *dev, struct tm *time); #ifdef __cplusplus } diff --git a/extras/fatfs/ff.c b/extras/fatfs/ff.c index ac1e571..faac347 100644 --- a/extras/fatfs/ff.c +++ b/extras/fatfs/ff.c @@ -1,13 +1,13 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12b / +/ FatFs - Generic FAT file system module R0.12c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2017, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided / that the following condition is met: - +/ / 1. Redistributions of source code must retain the above copyright notice, / this condition and the following disclaimer. / @@ -28,65 +28,11 @@ ---------------------------------------------------------------------------*/ -#if _FATFS != 68020 /* Revision ID */ +#if _FATFS != 68300 /* Revision ID */ #error Wrong include file (ff.h). #endif -#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } - - -/* Reentrancy related */ -#if _FS_REENTRANT -#if _USE_LFN == 1 -#error Static LFN work area cannot be used at thread-safe configuration -#endif -#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } -#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } -#else -#define ENTER_FF(fs) -#define LEAVE_FF(fs, res) return res -#endif - - - -/* Definitions of sector size */ -#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) -#error Wrong sector size configuration -#endif -#if _MAX_SS == _MIN_SS -#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ -#else -#define SS(fs) ((fs)->ssize) /* Variable sector size */ -#endif - - -/* Timestamp */ -#if _FS_NORTC == 1 -#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 -#error Invalid _FS_NORTC settings -#endif -#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) -#else -#define GET_FATTIME() get_fattime() -#endif - - -/* File lock controls */ -#if _FS_LOCK != 0 -#if _FS_READONLY -#error _FS_LOCK must be 0 at read-only configuration -#endif -typedef struct { - FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ - DWORD clu; /* Object ID 2, directory (0:root) */ - DWORD ofs; /* Object ID 3, directory offset */ - WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ -} FILESEM; -#endif - - - /* DBCS code ranges and SBCS upper conversion tables */ #if _CODE_PAGE == 932 /* Japanese Shift-JIS */ @@ -351,20 +297,20 @@ typedef struct { #endif /* _DF1S */ -/* File attribute bits (internal use) */ +/* Additional file attribute bits for internal use */ #define AM_VOL 0x08 /* Volume label */ #define AM_LFN 0x0F /* LFN entry */ #define AM_MASK 0x3F /* Mask of defined bits */ -/* File access control and file status flags (internal use) */ +/* Additional file access control and file status flags for internal use */ #define FA_SEEKEND 0x20 /* Seek to end of the file on file open */ #define FA_MODIFIED 0x40 /* File has been modified */ #define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */ -/* Name status flags */ -#define NSFLAG 11 /* Index of name status byte in fn[] */ +/* Name status flags in fn[] */ +#define NSFLAG 11 /* Index of the name status byte */ #define NS_LOSS 0x01 /* Out of 8.3 format */ #define NS_LFN 0x02 /* Force to create LFN entry */ #define NS_LAST 0x04 /* Last segment */ @@ -375,18 +321,17 @@ typedef struct { #define NS_NONAME 0x80 /* Not followed */ -/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */ -#define MAX_FAT12 0xFF5 /* Maximum number of FAT12 clusters */ -#define MAX_FAT16 0xFFF5 /* Maximum number of FAT16 clusters */ -#define MAX_FAT32 0xFFFFFF5 /* Maximum number of FAT32 clusters */ -#define MAX_EXFAT 0x7FFFFFFD /* Maximum number of exFAT clusters (limited by implementation) */ -#define MAX_DIR 0x200000 /* Maximum size of FAT directory */ -#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */ +/* Limits and boundaries */ +#define MAX_DIR 0x200000 /* Max size of FAT directory */ +#define MAX_DIR_EX 0x10000000 /* Max size of exFAT directory */ +#define MAX_FAT12 0xFF5 /* Max FAT12 clusters (differs from specs, but correct for real DOS/Windows behavior) */ +#define MAX_FAT16 0xFFF5 /* Max FAT16 clusters (differs from specs, but correct for real DOS/Windows behavior) */ +#define MAX_FAT32 0x0FFFFFF5 /* Max FAT32 clusters (not specified, practical limit) */ +#define MAX_EXFAT 0x7FFFFFFD /* Max exFAT clusters (differs from specs, implementation limit) */ -/* FatFs refers the members in the FAT structures as byte array instead of -/ structure members because the structure is not binary compatible between -/ different platforms */ +/* FatFs refers the FAT structure as simple byte array instead of structure member +/ because the C structure is not binary compatible between different platforms */ #define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */ #define BS_OEMName 3 /* OEM name (8-byte) */ @@ -432,19 +377,61 @@ typedef struct { #define BPB_FatSzEx 84 /* exFAT: FAT size [sector] (DWORD) */ #define BPB_DataOfsEx 88 /* exFAT: Data offset from top of the volume [sector] (DWORD) */ #define BPB_NumClusEx 92 /* exFAT: Number of clusters (DWORD) */ -#define BPB_RootClusEx 96 /* exFAT: Root directory cluster (DWORD) */ +#define BPB_RootClusEx 96 /* exFAT: Root directory start cluster (DWORD) */ #define BPB_VolIDEx 100 /* exFAT: Volume serial number (DWORD) */ #define BPB_FSVerEx 104 /* exFAT: File system version (WORD) */ #define BPB_VolFlagEx 106 /* exFAT: Volume flags (BYTE) */ #define BPB_ActFatEx 107 /* exFAT: Active FAT flags (BYTE) */ -#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in byte (BYTE) */ -#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in sector (BYTE) */ +#define BPB_BytsPerSecEx 108 /* exFAT: Log2 of sector size in unit of byte (BYTE) */ +#define BPB_SecPerClusEx 109 /* exFAT: Log2 of cluster size in unit of sector (BYTE) */ #define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */ #define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */ #define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */ #define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */ #define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */ +#define DIR_Name 0 /* Short file name (11-byte) */ +#define DIR_Attr 11 /* Attribute (BYTE) */ +#define DIR_NTres 12 /* Lower case flag (BYTE) */ +#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ +#define DIR_CrtTime 14 /* Created time (DWORD) */ +#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ +#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ +#define DIR_ModTime 22 /* Modified time (DWORD) */ +#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ +#define DIR_FileSize 28 /* File size (DWORD) */ +#define LDIR_Ord 0 /* LFN: LFN order and LLE flag (BYTE) */ +#define LDIR_Attr 11 /* LFN: LFN attribute (BYTE) */ +#define LDIR_Type 12 /* LFN: Entry type (BYTE) */ +#define LDIR_Chksum 13 /* LFN: Checksum of the SFN (BYTE) */ +#define LDIR_FstClusLO 26 /* LFN: MBZ field (WORD) */ +#define XDIR_Type 0 /* exFAT: Type of exFAT directory entry (BYTE) */ +#define XDIR_NumLabel 1 /* exFAT: Number of volume label characters (BYTE) */ +#define XDIR_Label 2 /* exFAT: Volume label (11-WORD) */ +#define XDIR_CaseSum 4 /* exFAT: Sum of case conversion table (DWORD) */ +#define XDIR_NumSec 1 /* exFAT: Number of secondary entries (BYTE) */ +#define XDIR_SetSum 2 /* exFAT: Sum of the set of directory entries (WORD) */ +#define XDIR_Attr 4 /* exFAT: File attribute (WORD) */ +#define XDIR_CrtTime 8 /* exFAT: Created time (DWORD) */ +#define XDIR_ModTime 12 /* exFAT: Modified time (DWORD) */ +#define XDIR_AccTime 16 /* exFAT: Last accessed time (DWORD) */ +#define XDIR_CrtTime10 20 /* exFAT: Created time subsecond (BYTE) */ +#define XDIR_ModTime10 21 /* exFAT: Modified time subsecond (BYTE) */ +#define XDIR_CrtTZ 22 /* exFAT: Created timezone (BYTE) */ +#define XDIR_ModTZ 23 /* exFAT: Modified timezone (BYTE) */ +#define XDIR_AccTZ 24 /* exFAT: Last accessed timezone (BYTE) */ +#define XDIR_GenFlags 33 /* exFAT: General secondary flags (WORD) */ +#define XDIR_NumName 35 /* exFAT: Number of file name characters (BYTE) */ +#define XDIR_NameHash 36 /* exFAT: Hash of file name (WORD) */ +#define XDIR_ValidFileSize 40 /* exFAT: Valid file size (QWORD) */ +#define XDIR_FstClus 52 /* exFAT: First cluster of the file data (DWORD) */ +#define XDIR_FileSize 56 /* exFAT: File/Directory size (QWORD) */ + +#define SZDIRE 32 /* Size of a directory entry */ +#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ +#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ + #define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */ #define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */ #define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */ @@ -463,47 +450,68 @@ typedef struct { #define PTE_StLba 8 /* MBR PTE: Start in LBA */ #define PTE_SizLba 12 /* MBR PTE: Size in LBA */ -#define DIR_Name 0 /* Short file name (11-byte) */ -#define DIR_Attr 11 /* Attribute (BYTE) */ -#define DIR_NTres 12 /* Lower case flag (BYTE) */ -#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */ -#define DIR_CrtTime 14 /* Created time (DWORD) */ -#define DIR_LstAccDate 18 /* Last accessed date (WORD) */ -#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */ -#define DIR_ModTime 22 /* Modified time (DWORD) */ -#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */ -#define DIR_FileSize 28 /* File size (DWORD) */ -#define LDIR_Ord 0 /* LFN entry order and LLE flag (BYTE) */ -#define LDIR_Attr 11 /* LFN attribute (BYTE) */ -#define LDIR_Type 12 /* LFN type (BYTE) */ -#define LDIR_Chksum 13 /* Checksum of the SFN entry (BYTE) */ -#define LDIR_FstClusLO 26 /* Must be zero (WORD) */ -#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */ -#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */ -#define XDIR_Label 2 /* Volume label (11-WORD) */ -#define XDIR_CaseSum 4 /* Sum of case conversion table (DWORD) */ -#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */ -#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */ -#define XDIR_Attr 4 /* File attribute (WORD) */ -#define XDIR_CrtTime 8 /* Created time (DWORD) */ -#define XDIR_ModTime 12 /* Modified time (DWORD) */ -#define XDIR_AccTime 16 /* Last accessed time (DWORD) */ -#define XDIR_CrtTime10 20 /* Created time subsecond (BYTE) */ -#define XDIR_ModTime10 21 /* Modified time subsecond (BYTE) */ -#define XDIR_CrtTZ 22 /* Created timezone (BYTE) */ -#define XDIR_ModTZ 23 /* Modified timezone (BYTE) */ -#define XDIR_AccTZ 24 /* Last accessed timezone (BYTE) */ -#define XDIR_GenFlags 33 /* Gneral secondary flags (WORD) */ -#define XDIR_NumName 35 /* Number of file name characters (BYTE) */ -#define XDIR_NameHash 36 /* Hash of file name (WORD) */ -#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */ -#define XDIR_FstClus 52 /* First cluster of the file data (DWORD) */ -#define XDIR_FileSize 56 /* File/Directory size (QWORD) */ -#define SZDIRE 32 /* Size of a directory entry */ -#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ -#define DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */ -#define RDDEM 0x05 /* Replacement of the character collides with DDEM */ +/* Post process after fatal error on file operation */ +#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); } + + +/* Reentrancy related */ +#if _FS_REENTRANT +#if _USE_LFN == 1 +#error Static LFN work area cannot be used at thread-safe configuration +#endif +#define ENTER_FF(fs) { if (!lock_fs(fs)) return FR_TIMEOUT; } +#define LEAVE_FF(fs, res) { unlock_fs(fs, res); return res; } +#else +#define ENTER_FF(fs) +#define LEAVE_FF(fs, res) return res +#endif + + +/* Definitions of volume - partition conversion */ +#if _MULTI_PARTITION +#define LD2PD(vol) VolToPart[vol].pd /* Get physical drive number */ +#define LD2PT(vol) VolToPart[vol].pt /* Get partition index */ +#else +#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ +#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ +#endif + + +/* Definitions of sector size */ +#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) || (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096) +#error Wrong sector size configuration +#endif +#if _MAX_SS == _MIN_SS +#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */ +#else +#define SS(fs) ((fs)->ssize) /* Variable sector size */ +#endif + + +/* Timestamp */ +#if _FS_NORTC == 1 +#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31 +#error Invalid _FS_NORTC settings +#endif +#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16) +#else +#define GET_FATTIME() get_fattime() +#endif + + +/* File lock controls */ +#if _FS_LOCK != 0 +#if _FS_READONLY +#error _FS_LOCK must be 0 at read-only configuration +#endif +typedef struct { + FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */ + DWORD clu; /* Object ID 2, containing directory (0:root) */ + DWORD ofs; /* Object ID 3, offset in the directory */ + WORD ctr; /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */ +} FILESEM; +#endif @@ -515,11 +523,11 @@ typedef struct { ---------------------------------------------------------------------------*/ -/* Remark: Variables here without initial value shall be guaranteed zero/null -/ at start-up. If not, either the linker or start-up routine being used is +/* Remark: Variables defined here without initial value shall be guaranteed +/ zero/null at start-up. If not, the linker option or start-up routine is / not compliance with C standard. */ -#if _VOLUMES < 1 || _VOLUMES > 9 +#if _VOLUMES < 1 || _VOLUMES > 10 #error Wrong _VOLUMES setting #endif static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */ @@ -533,27 +541,29 @@ static BYTE CurrVol; /* Current drive */ static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */ #endif -#if _USE_LFN == 0 /* Non-LFN configuration */ +#if _USE_LFN == 0 /* Non-LFN configuration */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() -#else + +#else /* LFN configuration */ #if _MAX_LFN < 12 || _MAX_LFN > 255 -#error Wrong _MAX_LFN setting +#error Wrong _MAX_LFN value #endif +#define MAXDIRB(nc) ((nc + 44U) / 15 * SZDIRE) #if _USE_LFN == 1 /* LFN enabled with static working buffer */ #if _FS_EXFAT -static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */ +static BYTE DirBuf[MAXDIRB(_MAX_LFN)]; /* Directory entry block scratchpad buffer */ #endif -static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ +static WCHAR LfnBuf[_MAX_LFN + 1]; /* LFN enabled with static working buffer */ #define DEF_NAMBUF #define INIT_NAMBUF(fs) #define FREE_NAMBUF() #elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */ #if _FS_EXFAT -#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19]; +#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[MAXDIRB(_MAX_LFN)]; #define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; } #define FREE_NAMBUF() #else @@ -565,7 +575,7 @@ static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ #elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */ #if _FS_EXFAT #define DEF_NAMBUF WCHAR *lfn; -#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } +#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + MAXDIRB(_MAX_LFN)); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); } #define FREE_NAMBUF() ff_memfree(lfn) #else #define DEF_NAMBUF WCHAR *lfn; @@ -575,8 +585,9 @@ static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */ #else #error Wrong _USE_LFN setting + #endif -#endif +#endif /* else _USE_LFN == 0 */ #ifdef _EXCVT static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */ @@ -684,7 +695,9 @@ void mem_cpy (void* dst, const void* src, UINT cnt) { const BYTE *s = (const BYTE*)src; if (cnt) { - do *d++ = *s++; while (--cnt); + do { + *d++ = *s++; + } while (--cnt); } } @@ -693,7 +706,9 @@ static void mem_set (void* dst, int val, UINT cnt) { BYTE *d = (BYTE*)dst; - do *d++ = (BYTE)val; while (--cnt); + do { + *d++ = (BYTE)val; + } while (--cnt); } /* Compare memory block */ @@ -728,7 +743,7 @@ int lock_fs ( FATFS* fs /* File system object */ ) { - return ff_req_grant(fs->sobj); + return (fs && ff_req_grant(fs->sobj)) ? 1 : 0; } @@ -1030,17 +1045,21 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste break; } } - if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the contiguous part? */ + if (obj->stat == 3 && cofs < obj->n_cont) { /* Is it in the 1st fragment? */ val = clst + 1; /* Generate the value */ break; } if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */ - if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; - val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + if (obj->n_frag != 0) { /* Is it on the growing edge? */ + val = 0x7FFFFFFF; /* Generate EOC */ + } else { + if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break; + val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF; + } break; } } - /* go next */ + /* go to default */ #endif default: val = 1; /* Internal error */ @@ -1069,7 +1088,6 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ BYTE *p; FRESULT res = FR_INT_ERR; - if (clst >= 2 && clst < fs->n_fatent) { /* Check if in valid range */ switch (fs->fs_type) { case FS_FAT12 : /* Bitfield items */ @@ -1120,12 +1138,12 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */ /* exFAT: Accessing FAT and Allocation Bitmap */ /*-----------------------------------------------------------------------*/ -/*---------------------------------------------*/ -/* exFAT: Find a contiguous free cluster block */ -/*---------------------------------------------*/ +/*--------------------------------------*/ +/* Find a contiguous free cluster block */ +/*--------------------------------------*/ static -DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */ +DWORD find_bitmap ( /* 0:Not found, 2..:Cluster block found, 0xFFFFFFFF:Disk error */ FATFS* fs, /* File system object */ DWORD clst, /* Cluster number to scan from */ DWORD ncl /* Number of contiguous clusters to find (1..) */ @@ -1146,12 +1164,12 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis do { bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */ if (++val >= fs->n_fatent - 2) { /* Next cluster (with wrap-around) */ - val = 0; bm = 0; i = 4096; + val = 0; bm = 0; i = SS(fs); } if (!bv) { /* Is it a free cluster? */ - if (++ctr == ncl) return scl + 2; /* Check run length */ + if (++ctr == ncl) return scl + 2; /* Check if run length is sufficient for required */ } else { - scl = val; ctr = 0; /* Encountered a live cluster, restart to scan */ + scl = val; ctr = 0; /* Encountered a cluster in-use, restart to scan */ } if (val == clst) return 0; /* All cluster scanned? */ } while (bm); @@ -1161,9 +1179,9 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis } -/*------------------------------------*/ -/* exFAT: Set/Clear a block of bitmap */ -/*------------------------------------*/ +/*----------------------------------------*/ +/* Set/Clear a block of allocation bitmap */ +/*----------------------------------------*/ static FRESULT change_bitmap ( @@ -1177,7 +1195,6 @@ FRESULT change_bitmap ( UINT i; DWORD sect; - clst -= 2; /* The first bit corresponds to cluster #2 */ sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */ i = clst / 8 % SS(fs); /* Byte offset in the sector */ @@ -1199,11 +1216,11 @@ FRESULT change_bitmap ( /*---------------------------------------------*/ -/* Complement contiguous part of the FAT chain */ +/* Fill the first fragment of the FAT chain */ /*---------------------------------------------*/ static -FRESULT fill_fat_chain ( +FRESULT fill_first_frag ( _FDID* obj /* Pointer to the corresponding object */ ) { @@ -1220,6 +1237,28 @@ FRESULT fill_fat_chain ( return FR_OK; } + +/*---------------------------------------------*/ +/* Fill the last fragment of the FAT chain */ +/*---------------------------------------------*/ + +static +FRESULT fill_last_frag ( + _FDID* obj, /* Pointer to the corresponding object */ + DWORD lcl, /* Last cluster of the fragment */ + DWORD term /* Value to set the last FAT entry */ +) +{ + FRESULT res; + + while (obj->n_frag > 0) { /* Create the last chain on the FAT */ + res = put_fat(obj->fs, lcl - obj->n_frag + 1, (obj->n_frag > 1) ? lcl - obj->n_frag + 2 : term); + if (res != FR_OK) return res; + obj->n_frag--; + } + return FR_OK; +} + #endif /* _FS_EXFAT && !_FS_READONLY */ @@ -1270,7 +1309,7 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ #if _FS_EXFAT || _USE_TRIM if (ecl + 1 == nxt) { /* Is next cluster contiguous? */ ecl = nxt; - } else { /* End of contiguous cluster block */ + } else { /* End of contiguous cluster block */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { res = change_bitmap(fs, scl, ecl - scl + 1, 0); /* Mark the cluster block 'free' on the bitmap */ @@ -1290,10 +1329,10 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - if (pclst == 0) { /* Does object have no chain? */ + if (pclst == 0) { /* Does the object have no chain? */ obj->stat = 0; /* Change the object status 'initial' */ } else { - if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain got contiguous? */ + if (obj->stat == 3 && pclst >= obj->sclust && pclst <= obj->sclust + obj->n_cont) { /* Did the chain get contiguous? */ obj->stat = 2; /* Change the object status 'contiguous' */ } } @@ -1325,7 +1364,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err } else { /* Stretch current chain */ cs = get_fat(obj, clst); /* Check the cluster status */ - if (cs < 2) return 1; /* Invalid value */ + if (cs < 2) return 1; /* Invalid FAT value */ if (cs == 0xFFFFFFFF) return cs; /* A disk error occurred */ if (cs < fs->n_fatent) return cs; /* It is already followed by next cluster */ scl = clst; @@ -1339,13 +1378,22 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err if (res == FR_INT_ERR) return 1; if (res == FR_DISK_ERR) return 0xFFFFFFFF; if (clst == 0) { /* Is it a new chain? */ - obj->stat = 2; /* Set status 'contiguous chain' */ - } else { /* This is a stretched chain */ + obj->stat = 2; /* Set status 'contiguous' */ + } else { /* It is a stretched chain */ if (obj->stat == 2 && ncl != scl + 1) { /* Is the chain got fragmented? */ obj->n_cont = scl - obj->sclust; /* Set size of the contiguous part */ obj->stat = 3; /* Change status 'just fragmented' */ } } + if (obj->stat != 2) { /* Is the file non-contiguous? */ + if (ncl == clst + 1) { /* Is the cluster next to previous one? */ + obj->n_frag = obj->n_frag ? obj->n_frag + 1 : 2; /* Increment size of last framgent */ + } else { /* New fragment */ + if (obj->n_frag == 0) obj->n_frag = 1; + res = fill_last_frag(obj, clst, ncl); /* Fill last fragment on the FAT and link it to new one */ + if (res == FR_OK) obj->n_frag = 1; + } + } } else #endif { /* On the FAT12/16/32 volume */ @@ -1361,23 +1409,18 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err if (cs == 1 || cs == 0xFFFFFFFF) return cs; /* An error occurred */ if (ncl == scl) return 0; /* No free cluster */ } - } - - if (_FS_EXFAT && fs->fs_type == FS_EXFAT && obj->stat == 2) { /* Is it a contiguous chain? */ - res = FR_OK; /* FAT does not need to be written */ - } else { res = put_fat(fs, ncl, 0xFFFFFFFF); /* Mark the new cluster 'EOC' */ - if (res == FR_OK && clst) { + if (res == FR_OK && clst != 0) { res = put_fat(fs, clst, ncl); /* Link it from the previous one if needed */ } } if (res == FR_OK) { /* Update FSINFO if function succeeded. */ fs->last_clst = ncl; - if (fs->free_clst < fs->n_fatent - 2) fs->free_clst--; + if (fs->free_clst <= fs->n_fatent - 2) fs->free_clst--; fs->fsi_flag |= 1; } else { - ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Create error status */ + ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1; /* Failed. Generate error status */ } return ncl; /* Return new cluster number or error status */ @@ -1519,7 +1562,7 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou } fs->winsect -= n; /* Restore window offset */ #else - if (!stretch) dp->sect = 0; /* If no stretch, report EOT (this is to suppress warning) */ + if (!stretch) dp->sect = 0; /* (this line is to suppress compiler warning) */ dp->sect = 0; return FR_NO_FILE; /* Report EOT */ #endif } @@ -1676,9 +1719,9 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */ WCHAR wc, uc; - if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */ + if (ld_word(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO is 0 */ - i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ + i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Offset in the LFN buffer */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */ uc = ld_word(dir + LfnOfs[s]); /* Pick an LFN character */ @@ -1809,7 +1852,9 @@ BYTE sum_sfn ( BYTE sum = 0; UINT n = 11; - do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n); + do { + sum = (sum >> 1) + (sum << 7) + *dir++; + } while (--n); return sum; } @@ -1893,30 +1938,26 @@ void get_xdir_info ( #endif /* Get file name */ + di = 0; #if _LFN_UNICODE - if (dirb[XDIR_NumName] <= _MAX_LFN) { - for (si = SZDIRE * 2, di = 0; di < dirb[XDIR_NumName]; si += 2, di++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - fno->fname[di] = w; /* Store it */ - } - } else { - di = 0; /* Buffer overflow and inaccessible object */ + for (si = SZDIRE * 2; di < dirb[XDIR_NumName]; si += 2, di++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ld_word(dirb + si); /* Get a character */ + if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow --> inaccessible object name */ + fno->fname[di] = w; /* Store it */ } #else - for (si = SZDIRE * 2, di = nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { - if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ - w = ld_word(dirb + si); /* Get a character */ - w = ff_convert(w, 0); /* Unicode -> OEM */ - if (w == 0) { di = 0; break; } /* Could not be converted and inaccessible object */ - if (_DF1S && w >= 0x100) { /* Put 1st byte if it is a DBC (always false at SBCS cfg) */ - fno->fname[di++] = (char)(w >> 8); + for (si = SZDIRE * 2, nc = 0; nc < dirb[XDIR_NumName]; si += 2, nc++) { + if ((si % SZDIRE) == 0) si += 2; /* Skip entry type field */ + w = ff_convert(ld_word(dirb + si), 0); /* Get a character and Unicode -> OEM */ + if (_DF1S && w >= 0x100) { /* Is it a double byte char? (always false at SBCS cfg) */ + fno->fname[di++] = (char)(w >> 8); /* Put 1st byte of the DBC */ } - if (di >= _MAX_LFN) { di = 0; break; } /* Buffer overflow and inaccessible object */ + if (w == 0 || di >= _MAX_LFN) { di = 0; break; } /* Invalid char or buffer overflow --> inaccessible object name */ fno->fname[di++] = (char)w; } #endif - if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object? */ + if (di == 0) fno->fname[di++] = '?'; /* Inaccessible object name? */ fno->fname[di] = 0; /* Terminate file name */ fno->altname[0] = 0; /* No SFN */ @@ -1939,7 +1980,7 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ ) { FRESULT res; - UINT i, nent; + UINT i, sz_ent; BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the on-memory direcotry entry block 85+C0+C1s */ @@ -1947,8 +1988,9 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR; - mem_cpy(dirb, dp->dir, SZDIRE); - nent = dirb[XDIR_NumSec] + 1; + mem_cpy(dirb + 0, dp->dir, SZDIRE); + sz_ent = (dirb[XDIR_NumSec] + 1) * SZDIRE; + if (sz_ent < 3 * SZDIRE || sz_ent > 19 * SZDIRE) return FR_INT_ERR; /* Load C0 entry */ res = dir_next(dp, 0); @@ -1957,40 +1999,39 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */ if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != 0xC0) return FR_INT_ERR; mem_cpy(dirb + SZDIRE, dp->dir, SZDIRE); + if (MAXDIRB(dirb[XDIR_NumName]) > sz_ent) return FR_INT_ERR; /* Load C1 entries */ - if (nent < 3 || nent > 19) return FR_NO_FILE; - i = SZDIRE * 2; nent *= SZDIRE; + i = SZDIRE * 2; /* C1 offset */ do { res = dir_next(dp, 0); if (res != FR_OK) return res; res = move_window(dp->obj.fs, dp->sect); if (res != FR_OK) return res; if (dp->dir[XDIR_Type] != 0xC1) return FR_INT_ERR; - mem_cpy(dirb + i, dp->dir, SZDIRE); - i += SZDIRE; - } while (i < nent); - - /* Sanity check */ - if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + if (i < MAXDIRB(_MAX_LFN)) mem_cpy(dirb + i, dp->dir, SZDIRE); + } while ((i += SZDIRE) < sz_ent); + /* Sanity check (do it when accessible object name) */ + if (i <= MAXDIRB(_MAX_LFN)) { + if (xdir_sum(dirb) != ld_word(dirb + XDIR_SetSum)) return FR_INT_ERR; + } return FR_OK; } -#if !_FS_READONLY || _FS_RPATH != 0 +#if !_FS_READONLY || _FS_RPATH != 0 /*------------------------------------------------*/ /* exFAT: Load the object's directory entry block */ /*------------------------------------------------*/ static FRESULT load_obj_dir ( DIR* dp, /* Blank directory object to be used to access containing direcotry */ - const _FDID* obj /* Object with containing directory information */ + const _FDID* obj /* Object with its containing directory information */ ) { FRESULT res; - /* Open object containing directory */ dp->obj.fs = obj->fs; dp->obj.sclust = obj->c_scl; @@ -1998,7 +2039,7 @@ FRESULT load_obj_dir ( dp->obj.objsize = obj->c_size & 0xFFFFFF00; dp->blk_ofs = obj->c_ofs; - res = dir_sdi(dp, dp->blk_ofs); /* Goto the block location */ + res = dir_sdi(dp, dp->blk_ofs); /* Goto object's entry block */ if (res == FR_OK) { res = load_xdir(dp); /* Load the object's entry block */ } @@ -2055,24 +2096,25 @@ void create_xdir ( WCHAR chr; - mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */ + /* Create 85+C0 entry */ + mem_set(dirb, 0, 2 * SZDIRE); dirb[XDIR_Type] = 0x85; dirb[XDIR_Type + SZDIRE] = 0xC0; - st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ - i = SZDIRE * 2; /* C1 offset */ - nc = 0; nb = 1; chr = 1; + /* Create C1 entries */ + nc = 0; nb = 1; chr = 1; i = SZDIRE * 2; do { dirb[i++] = 0xC1; dirb[i++] = 0; /* Entry type C1 */ do { /* Fill name field */ if (chr && (chr = lfn[nc]) != 0) nc++; /* Get a character if exist */ - st_word(dirb + i, chr); i += 2; /* Store it */ - } while (i % SZDIRE); + st_word(dirb + i, chr); /* Store it */ + } while ((i += 2) % SZDIRE != 0); nb++; } while (lfn[nc]); /* Fill next entry if any char follows */ dirb[XDIR_NumName] = nc; /* Set name length */ - dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */ + dirb[XDIR_NumSec] = nb; /* Set block length */ + st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */ } #endif /* !_FS_READONLY */ @@ -2102,7 +2144,9 @@ FRESULT dir_read ( res = move_window(fs, dp->sect); if (res != FR_OK) break; c = dp->dir[DIR_Name]; /* Test for the entry type */ - if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */ + if (c == 0) { + res = FR_NO_FILE; break; /* Reached to end of the directory */ + } #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ if (_USE_LABEL && vol) { @@ -2183,7 +2227,10 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */ WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */ while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */ - if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */ +#if _MAX_LFN < 255 + if (fs->dirbuf[XDIR_NumName] > _MAX_LFN) continue; /* Skip comparison if inaccessible object name */ +#endif + if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip comparison if hash mismatched */ for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */ if ((di % SZDIRE) == 0) di += 2; if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break; @@ -2254,7 +2301,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */ - for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ + for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */ @@ -2263,19 +2310,20 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */ res = dir_alloc(dp, nent); /* Allocate entries */ if (res != FR_OK) return res; - dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */ + dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set the allocated entry block offset */ if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */ - dp->obj.stat &= 3; - dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */ - res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */ + dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase the directory size by cluster size */ + res = fill_first_frag(&dp->obj); /* Fill first fragment on the FAT if needed */ + if (res != FR_OK) return res; + res = fill_last_frag(&dp->obj, dp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + if (res != FR_OK) return res; + res = load_obj_dir(&dj, &dp->obj); /* Load the object status */ if (res != FR_OK) return res; - res = load_obj_dir(&dj, &dp->obj); - if (res != FR_OK) return res; /* Load the object status */ st_qword(fs->dirbuf + XDIR_FileSize, dp->obj.objsize); /* Update the allocation status */ st_qword(fs->dirbuf + XDIR_ValidFileSize, dp->obj.objsize); fs->dirbuf[XDIR_GenFlags] = dp->obj.stat | 1; - res = store_xdir(&dj); /* Store the object status */ + res = store_xdir(&dj); /* Store the object status */ if (res != FR_OK) return res; } @@ -2454,7 +2502,7 @@ void get_fileinfo ( /* No return code */ #endif fno->altname[j] = c; if (!lfv) { - if (IsUpper(c) && (dp->dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY))) { + if (IsUpper(c) && (dp->dir[DIR_NTres] & ((i >= 9) ? NS_EXT : NS_BODY))) { c += 0x20; /* To lower */ } fno->fname[j] = c; @@ -2775,14 +2823,16 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ #if _FS_RPATH != 0 if (*path != '/' && *path != '\\') { /* Without heading separator */ - obj->sclust = fs->cdir; /* Start from the current directory */ + obj->sclust = fs->cdir; /* Start from current directory */ } else #endif { /* With heading separator */ while (*path == '/' || *path == '\\') path++; /* Strip heading separator */ - obj->sclust = 0; /* Start from the root directory */ + obj->sclust = 0; /* Start from root directory */ } -#if _FS_EXFAT && _FS_RPATH != 0 +#if _FS_EXFAT + obj->n_frag = 0; /* Invalidate last fragment counter of the object */ +#if _FS_RPATH != 0 if (fs->fs_type == FS_EXFAT && obj->sclust) { /* Retrieve the sub-directory status if needed */ DIR dj; @@ -2794,6 +2844,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ obj->objsize = ld_dword(fs->dirbuf + XDIR_FileSize); obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; } +#endif #endif if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */ @@ -2824,8 +2875,8 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */ res = FR_NO_PATH; break; } #if _FS_EXFAT - if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory information for next dir */ + if (fs->fs_type == FS_EXFAT) { /* Save containing directory information for next dir */ + obj->c_scl = obj->sclust; obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; obj->c_ofs = dp->blk_ofs; obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Open next directory */ @@ -2858,7 +2909,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ UINT i; int vol = -1; #if _STR_VOLUME_ID /* Find string drive id */ - static const char* const str[] = {_VOLUME_STRS}; + static const char* const volid[] = {_VOLUME_STRS}; const char *sp; char c; TCHAR tc; @@ -2869,7 +2920,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++) ; /* Find ':' in the path */ if (*tt == ':') { /* If a ':' is exist in the path name */ tp = *path; - i = *tp++ - '0'; + i = *tp++ - '0'; if (i < 10 && tp == tt) { /* Is there a numeric drive id? */ if (i < _VOLUMES) { /* If a drive id is found, get the value and strip it */ vol = (int)i; @@ -2880,7 +2931,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ else { /* No numeric drive number, find string drive id */ i = 0; tt++; do { - sp = str[i]; tp = *path; + sp = volid[i]; tp = *path; do { /* Compare a string drive id with path name */ c = *sp++; tc = *tp++; if (IsLower(tc)) tc -= 0x20; @@ -2913,13 +2964,13 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */ static BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */ FATFS* fs, /* File system object */ - DWORD sect /* Sector# (lba) to check if it is an FAT-VBR or not */ + DWORD sect /* Sector# (lba) to load and check if it is an FAT-VBR or not */ ) { fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */ if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */ - if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */ + if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed here even if the sector size is >512) */ if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) { if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */ @@ -2989,29 +3040,30 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (!_FS_READONLY && mode && (stat & STA_PROTECT)) { /* Check disk write protection if needed */ return FR_WRITE_PROTECTED; } -#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ +#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR; if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) return FR_DISK_ERR; #endif - /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */ + + /* Find an FAT partition on the drive. Supports only generic partitioning rules, FDISK and SFD. */ bsect = 0; fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR or forced partition number */ - for (i = 0; i < 4; i++) { /* Get partition offset */ + for (i = 0; i < 4; i++) { /* Get partition offset */ pt = fs->win + (MBR_Table + i * SZ_PTE); br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0; } - i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ + i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */ if (i) i--; - do { /* Find an FAT volume */ + do { /* Find an FAT volume */ bsect = br[i]; fmt = bsect ? check_fs(fs, bsect) : 3; /* Check the partition */ - } while (!LD2PT(vol) && fmt >= 2 && ++i < 4); + } while (LD2PT(vol) == 0 && fmt >= 2 && ++i < 4); } if (fmt == 4) return FR_DISK_ERR; /* An error occured in the disk I/O layer */ if (fmt >= 2) return FR_NO_FILESYSTEM; /* No FAT volume is found */ - /* An FAT volume is found. Following code initializes the file system object */ + /* An FAT volume is found (bsect). Following code initializes the file system object */ #if _FS_EXFAT if (fmt == 1) { @@ -3022,8 +3074,9 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */ - if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ + if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) { /* (BPB_BytsPerSecEx must be equal to the physical sector size) */ return FR_NO_FILESYSTEM; + } maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */ if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */ @@ -3062,49 +3115,49 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ { if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */ - fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ + fasize = ld_word(fs->win + BPB_FATSz16); /* Number of sectors per FAT */ if (fasize == 0) fasize = ld_dword(fs->win + BPB_FATSz32); fs->fsize = fasize; - fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ + fs->n_fats = fs->win[BPB_NumFATs]; /* Number of FATs */ if (fs->n_fats != 1 && fs->n_fats != 2) return FR_NO_FILESYSTEM; /* (Must be 1 or 2) */ - fasize *= fs->n_fats; /* Number of sectors for FAT area */ + fasize *= fs->n_fats; /* Number of sectors for FAT area */ - fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ + fs->csize = fs->win[BPB_SecPerClus]; /* Cluster size */ if (fs->csize == 0 || (fs->csize & (fs->csize - 1))) return FR_NO_FILESYSTEM; /* (Must be power of 2) */ fs->n_rootdir = ld_word(fs->win + BPB_RootEntCnt); /* Number of root directory entries */ if (fs->n_rootdir % (SS(fs) / SZDIRE)) return FR_NO_FILESYSTEM; /* (Must be sector aligned) */ - tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ + tsect = ld_word(fs->win + BPB_TotSec16); /* Number of sectors on the volume */ if (tsect == 0) tsect = ld_dword(fs->win + BPB_TotSec32); - nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ - if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ + nrsv = ld_word(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */ + if (nrsv == 0) return FR_NO_FILESYSTEM; /* (Must not be 0) */ /* Determine the FAT sub type */ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZDIRE); /* RSV + FAT + DIR */ - if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ - nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ - if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ + nclst = (tsect - sysect) / fs->csize; /* Number of clusters */ + if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */ fmt = FS_FAT32; if (nclst <= MAX_FAT16) fmt = FS_FAT16; if (nclst <= MAX_FAT12) fmt = FS_FAT12; /* Boundaries and Limits */ - fs->n_fatent = nclst + 2; /* Number of FAT entries */ - fs->volbase = bsect; /* Volume start sector */ - fs->fatbase = bsect + nrsv; /* FAT start sector */ - fs->database = bsect + sysect; /* Data start sector */ + fs->n_fatent = nclst + 2; /* Number of FAT entries */ + fs->volbase = bsect; /* Volume start sector */ + fs->fatbase = bsect + nrsv; /* FAT start sector */ + fs->database = bsect + sysect; /* Data start sector */ if (fmt == FS_FAT32) { if (ld_word(fs->win + BPB_FSVer32) != 0) return FR_NO_FILESYSTEM; /* (Must be FAT32 revision 0.0) */ - if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ + if (fs->n_rootdir) return FR_NO_FILESYSTEM; /* (BPB_RootEntCnt must be 0) */ fs->dirbase = ld_dword(fs->win + BPB_RootClus32); /* Root directory start cluster */ - szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ + szbfat = fs->n_fatent * 4; /* (Needed FAT size) */ } else { if (fs->n_rootdir == 0) return FR_NO_FILESYSTEM;/* (BPB_RootEntCnt must not be 0) */ - fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ - szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ + fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */ + szbfat = (fmt == FS_FAT16) ? /* (Needed FAT size) */ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1); } if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */ @@ -3135,18 +3188,18 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */ #endif /* !_FS_READONLY */ } - fs->fs_type = fmt; /* FAT sub-type */ - fs->id = ++Fsid; /* File system mount ID */ + fs->fs_type = fmt; /* FAT sub-type */ + fs->id = ++Fsid; /* File system mount ID */ #if _USE_LFN == 1 fs->lfnbuf = LfnBuf; /* Static LFN working buffer */ #if _FS_EXFAT - fs->dirbuf = DirBuf; /* Static directory block working buuffer */ + fs->dirbuf = DirBuf; /* Static directory block scratchpad buuffer */ #endif #endif #if _FS_RPATH != 0 - fs->cdir = 0; /* Initialize current directory */ + fs->cdir = 0; /* Initialize current directory */ #endif -#if _FS_LOCK != 0 /* Clear file lock semaphores */ +#if _FS_LOCK != 0 /* Clear file lock semaphores */ clear_lock(fs); #endif return FR_OK; @@ -3167,14 +3220,13 @@ FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */ { FRESULT res; - if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) { - *fs = 0; /* The object is invalid */ - res = FR_INVALID_OBJECT; + *fs = 0; + res = FR_INVALID_OBJECT; /* The object is invalid */ } else { *fs = obj->fs; /* Owner file sytem object */ ENTER_FF(obj->fs); /* Lock file system */ - res = FR_OK; + res = FR_OK; /* Valid object */ } return res; } @@ -3281,12 +3333,13 @@ FRESULT f_open ( /* Create or Open a file */ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) { if (res != FR_OK) { /* No file, create new */ - if (res == FR_NO_FILE) /* There is no file to open, create a new entry */ + if (res == FR_NO_FILE) { /* There is no file to open, create a new entry */ #if _FS_LOCK != 0 res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES; #else res = dir_register(&dj); #endif + } mode |= FA_CREATE_ALWAYS; /* File is created */ } else { /* Any object is already existing */ @@ -3305,6 +3358,7 @@ FRESULT f_open ( fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; + fp->obj.n_frag = 0; /* Initialize directory entry block */ st_dword(fs->dirbuf + XDIR_CrtTime, dw); /* Set created time */ fs->dirbuf[XDIR_CrtTime10] = 0; @@ -3379,16 +3433,16 @@ FRESULT f_open ( if (res == FR_OK) { #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get allocation info */ - fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); - fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; - fp->obj.c_scl = dj.obj.sclust; + fp->obj.c_scl = dj.obj.sclust; /* Get containing directory info */ fp->obj.c_size = ((DWORD)dj.obj.objsize & 0xFFFFFF00) | dj.obj.stat; fp->obj.c_ofs = dj.blk_ofs; + fp->obj.sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */ + fp->obj.objsize = ld_qword(fs->dirbuf + XDIR_FileSize); + fp->obj.stat = fs->dirbuf[XDIR_GenFlags] & 2; } else #endif { - fp->obj.sclust = ld_clust(fs, dj.dir); /* Get allocation info */ + fp->obj.sclust = ld_clust(fs, dj.dir); /* Get object allocation info */ fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize); } #if _USE_FASTSEEK @@ -3672,8 +3726,10 @@ FRESULT f_sync ( FATFS *fs; DWORD tm; BYTE *dir; +#if _FS_EXFAT + DIR dj; DEF_NAMBUF - +#endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ if (res == FR_OK) { @@ -3688,10 +3744,11 @@ FRESULT f_sync ( tm = GET_FATTIME(); /* Modified time */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - res = fill_fat_chain(&fp->obj); /* Create FAT chain if needed */ + res = fill_first_frag(&fp->obj); /* Fill first fragment on the FAT if needed */ + if (res == FR_OK) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } if (res == FR_OK) { - DIR dj; - INIT_NAMBUF(fs); res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */ if (res == FR_OK) { @@ -3944,7 +4001,14 @@ FRESULT f_lseek ( #endif res = validate(&fp->obj, &fs); /* Check validity of the file object */ - if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */ + if (res == FR_OK) res = (FRESULT)fp->err; +#if _FS_EXFAT && !_FS_READONLY + if (res == FR_OK && fs->fs_type == FS_EXFAT) { + res = fill_last_frag(&fp->obj, fp->clust, 0xFFFFFFFF); /* Fill last fragment on the FAT if needed */ + } +#endif + if (res != FR_OK) LEAVE_FF(fs, res); + #if _USE_FASTSEEK if (fp->cltbl) { /* Fast seek */ if (ofs == CREATE_LINKMAP) { /* Create CLMT */ @@ -4109,16 +4173,16 @@ FRESULT f_opendir ( if (obj->attr & AM_DIR) { /* This object is a sub-directory */ #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { - obj->c_scl = obj->sclust; /* Save containing directory inforamation */ + obj->c_scl = obj->sclust; /* Get containing directory inforamation */ obj->c_size = ((DWORD)obj->objsize & 0xFFFFFF00) | obj->stat; obj->c_ofs = dp->blk_ofs; - obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object location and status */ + obj->sclust = ld_dword(fs->dirbuf + XDIR_FstClus); /* Get object allocation info */ obj->objsize = ld_qword(fs->dirbuf + XDIR_FileSize); obj->stat = fs->dirbuf[XDIR_GenFlags] & 2; } else #endif { - obj->sclust = ld_clust(fs, dp->dir); /* Get object location */ + obj->sclust = ld_clust(fs, dp->dir); /* Get object allocation info */ } } else { /* This object is a file */ res = FR_NO_PATH; @@ -4410,7 +4474,7 @@ FRESULT f_truncate ( if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */ - if (fp->obj.objsize > fp->fptr) { + if (fp->fptr < fp->obj.objsize) { /* Process when fptr is not on the eof */ if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */ res = remove_chain(&fp->obj, fp->obj.sclust, 0); fp->obj.sclust = 0; @@ -4493,7 +4557,7 @@ FRESULT f_unlink ( { dclst = ld_clust(fs, dj.dir); } - if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory ? */ + if (dj.obj.attr & AM_DIR) { /* Is it a sub-directory? */ #if _FS_RPATH != 0 if (dclst == fs->cdir) { /* Is it the current directory? */ res = FR_DENIED; @@ -4597,7 +4661,9 @@ FRESULT f_mkdir ( mem_set(dir, 0, SS(fs)); } } - if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */ + if (res == FR_OK) { + res = dir_register(&dj); /* Register the object to the directoy */ + } if (res == FR_OK) { #if _FS_EXFAT if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */ @@ -4617,7 +4683,9 @@ FRESULT f_mkdir ( dir[DIR_Attr] = AM_DIR; /* Attribute */ fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } else { remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */ } @@ -4648,7 +4716,7 @@ FRESULT f_rename ( DEF_NAMBUF - get_ldnumber(&path_new); /* Ignore drive number of new name */ + get_ldnumber(&path_new); /* Snip drive number of new name off */ res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive of the old object */ if (res == FR_OK) { djo.obj.fs = fs; @@ -4656,7 +4724,9 @@ FRESULT f_rename ( res = follow_path(&djo, path_old); /* Check old object */ if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */ #if _FS_LOCK != 0 - if (res == FR_OK) res = chk_lock(&djo, 2); + if (res == FR_OK) { + res = chk_lock(&djo, 2); + } #endif if (res == FR_OK) { /* Object to be renamed is found */ #if _FS_EXFAT @@ -4678,7 +4748,7 @@ FRESULT f_rename ( mem_cpy(fs->dirbuf, buf, SZDIRE * 2); fs->dirbuf[XDIR_NumSec] = nf; fs->dirbuf[XDIR_NumName] = nn; st_word(fs->dirbuf + XDIR_NameHash, nh); -/* Start of critical section where any interruption can cause a cross-link */ +/* Start of critical section where an interruption can cause a cross-link */ res = store_xdir(&djn); } } @@ -4703,7 +4773,7 @@ FRESULT f_rename ( if (!dw) { res = FR_INT_ERR; } else { -/* Start of critical section where any interruption can cause a cross-link */ +/* Start of critical section where an interruption can cause a cross-link */ res = move_window(fs, dw); dir = fs->win + SZDIRE * 1; /* Ptr to .. entry */ if (res == FR_OK && dir[1] == '.') { @@ -4721,7 +4791,7 @@ FRESULT f_rename ( res = sync_fs(fs); } } -/* End of critical section */ +/* End of the critical section */ } FREE_NAMBUF(); } @@ -4771,7 +4841,9 @@ FRESULT f_chmod ( dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */ fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4814,7 +4886,9 @@ FRESULT f_utime ( st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime); fs->wflag = 1; } - if (res == FR_OK) res = sync_fs(fs); + if (res == FR_OK) { + res = sync_fs(fs); + } } FREE_NAMBUF(); } @@ -4902,9 +4976,14 @@ FRESULT f_getlabel ( res = move_window(fs, fs->volbase); if (res == FR_OK) { switch (fs->fs_type) { - case FS_EXFAT: di = BPB_VolIDEx; break; - case FS_FAT32: di = BS_VolID32; break; - default: di = BS_VolID; + case FS_EXFAT: + di = BPB_VolIDEx; break; + + case FS_FAT32: + di = BS_VolID32; break; + + default: + di = BS_VolID; } *vsn = ld_dword(fs->win + di); } @@ -5074,11 +5153,11 @@ FRESULT f_expand ( scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */ if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */ if (scl == 0xFFFFFFFF) res = FR_DISK_ERR; - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */ lclst = scl + tcl - 1; - } else { + } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } @@ -5098,14 +5177,14 @@ FRESULT f_expand ( } if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */ } - if (res == FR_OK) { - if (opt) { + if (res == FR_OK) { /* A contiguous free area is found */ + if (opt) { /* Allocate it now */ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1); if (res != FR_OK) break; lclst = clst; } - } else { + } else { /* Set it as suggested point for next allocation */ lclst = scl - 1; } } @@ -5113,12 +5192,12 @@ FRESULT f_expand ( if (res == FR_OK) { fs->last_clst = lclst; /* Set suggested start cluster to start next */ - if (opt) { + if (opt) { /* Is it allocated now? */ fp->obj.sclust = scl; /* Update object allocation information */ fp->obj.objsize = fsz; if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */ fp->flag |= FA_MODIFIED; - if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */ + if (fs->free_clst <= fs->n_fatent - 2) { /* Update FSINFO */ fs->free_clst -= tcl; fs->fsi_flag |= 1; } @@ -5205,13 +5284,13 @@ FRESULT f_forward ( #if _USE_MKFS && !_FS_READONLY /*-----------------------------------------------------------------------*/ -/* Create FAT file system on the logical drive */ +/* Create an FAT/exFAT volume */ /*-----------------------------------------------------------------------*/ FRESULT f_mkfs ( const TCHAR* path, /* Logical drive number */ BYTE opt, /* Format option */ - DWORD au, /* Size of allocation unit [byte] */ + DWORD au, /* Size of allocation unit (cluster) [byte] */ void* work, /* Pointer to working buffer */ UINT len /* Size of working buffer */ ) @@ -5236,7 +5315,7 @@ FRESULT f_mkfs ( /* Check mounted drive and clear work area */ vol = get_ldnumber(&path); /* Get target logical drive */ if (vol < 0) return FR_INVALID_DRIVE; - if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear mounted volume */ + if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear the volume */ pdrv = LD2PD(vol); /* Physical drive */ part = LD2PT(vol); /* Partition (0:create as new, 1-4:get from partition table) */ @@ -5245,7 +5324,7 @@ FRESULT f_mkfs ( if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1; /* Erase block to align data area */ -#if _MAX_SS != _MIN_SS /* Get sector size of the medium */ +#if _MAX_SS != _MIN_SS /* Get sector size of the medium if variable sector size cfg. */ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR; if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR; #else @@ -5304,7 +5383,7 @@ FRESULT f_mkfs ( if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */ #if _USE_TRIM - tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */ + tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area may be erased */ disk_ioctl(pdrv, CTRL_TRIM, tbl); #endif /* Determine FAT location, data location and number of clusters */ @@ -5340,11 +5419,12 @@ FRESULT f_mkfs ( ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */ } st = 1; /* Do not compress short run */ - /* continue */ + /* go to next case */ case 1: ch = si++; /* Fill the short run */ if (--j == 0) st = 0; break; + default: ch = (WCHAR)j; si += j; /* Number of chars to skip */ st = 0; @@ -5626,14 +5706,14 @@ FRESULT f_mkfs ( } } - if (_MULTI_PARTITION && part != 0) { + /* Update partition information */ + if (_MULTI_PARTITION && part != 0) { /* Created in the existing partition */ /* Update system ID in the partition table */ if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */ - buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system type */ + buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system ID */ if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */ - } else { - if (!(opt & FM_SFD)) { - /* Create partition table in FDISK format */ + } else { /* Created as a new single partition */ + if (!(opt & FM_SFD)) { /* Create partition table if in FDISK format */ mem_set(buf, 0, ss); st_word(buf + BS_55AA, 0xAA55); /* MBR signature */ pte = buf + MBR_Table; /* Create partition table for single partition in the drive */ @@ -5642,7 +5722,7 @@ FRESULT f_mkfs ( pte[PTE_StSec] = 1; /* Start sector */ pte[PTE_StCyl] = 0; /* Start cylinder */ pte[PTE_System] = sys; /* System type */ - n = (b_vol + sz_vol) / (63 * 255); /* (End CHS is incorrect) */ + n = (b_vol + sz_vol) / (63 * 255); /* (End CHS may be invalid) */ pte[PTE_EdHead] = 254; /* End head */ pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */ pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */ @@ -5681,7 +5761,7 @@ FRESULT f_fdisk ( if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk)) return FR_DISK_ERR; - /* Determine the CHS without any care of the drive geometry */ + /* Determine the CHS without any consideration of the drive geometry */ for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ; if (n == 256) n--; e_hd = n - 1; @@ -5692,7 +5772,7 @@ FRESULT f_fdisk ( mem_set(buf, 0, _MAX_SS); p = buf + MBR_Table; b_cyl = 0; for (i = 0; i < 4; i++, p += SZ_PTE) { - p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; + p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl; /* Number of cylinders */ if (!p_cyl) continue; s_part = (DWORD)sz_cyl * b_cyl; sz_part = (DWORD)sz_cyl * p_cyl; @@ -5702,19 +5782,19 @@ FRESULT f_fdisk ( } else { s_hd = 0; } - e_cyl = b_cyl + p_cyl - 1; + e_cyl = b_cyl + p_cyl - 1; /* End cylinder */ if (e_cyl >= tot_cyl) return FR_INVALID_PARAMETER; /* Set partition table */ p[1] = s_hd; /* Start head */ p[2] = (BYTE)((b_cyl >> 2) + 1); /* Start sector */ p[3] = (BYTE)b_cyl; /* Start cylinder */ - p[4] = 0x06; /* System type (temporary setting) */ + p[4] = 0x07; /* System type (temporary setting) */ p[5] = e_hd; /* End head */ p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */ p[7] = (BYTE)e_cyl; /* End cylinder */ st_dword(p + 8, s_part); /* Start sector in LBA */ - st_dword(p + 12, sz_part); /* Partition size */ + st_dword(p + 12, sz_part); /* Number of sectors */ /* Next partition */ b_cyl += p_cyl; @@ -5756,17 +5836,17 @@ TCHAR* f_gets ( c = s[0]; if (c >= 0x80) { if (c < 0xC0) continue; /* Skip stray trailer */ - if (c < 0xE0) { /* Two-byte sequence */ + if (c < 0xE0) { /* Two-byte sequence (0x80-0x7FF) */ f_read(fp, s, 1, &rc); if (rc != 1) break; c = (c & 0x1F) << 6 | (s[0] & 0x3F); - if (c < 0x80) c = '?'; + if (c < 0x80) c = '?'; /* Reject invalid code range */ } else { - if (c < 0xF0) { /* Three-byte sequence */ + if (c < 0xF0) { /* Three-byte sequence (0x800-0xFFFF) */ f_read(fp, s, 2, &rc); if (rc != 2) break; c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); - if (c < 0x800) c = '?'; + if (c < 0x800) c = '?'; /* Reject invalid code range */ } else { /* Reject four-byte sequence */ c = '?'; } @@ -5998,17 +6078,23 @@ int f_printf ( while (*p) putc_bfd(&pb, *p++); while (j++ < w) putc_bfd(&pb, ' '); continue; + case 'C' : /* Character */ putc_bfd(&pb, (TCHAR)va_arg(arp, int)); continue; + case 'B' : /* Binary */ r = 2; break; + case 'O' : /* Octal */ r = 8; break; + case 'D' : /* Signed decimal */ case 'U' : /* Unsigned decimal */ r = 10; break; + case 'X' : /* Hexdecimal */ r = 16; break; + default: /* Unknown type (pass-through) */ putc_bfd(&pb, c); continue; } @@ -6028,7 +6114,9 @@ int f_printf ( if (f & 8) str[i++] = '-'; j = i; d = (f & 1) ? '0' : ' '; while (!(f & 2) && j++ < w) putc_bfd(&pb, d); - do putc_bfd(&pb, str[--i]); while (i); + do { + putc_bfd(&pb, str[--i]); + } while (i); while (j++ < w) putc_bfd(&pb, d); } diff --git a/extras/fatfs/ff.h b/extras/fatfs/ff.h index 981a886..f902519 100644 --- a/extras/fatfs/ff.h +++ b/extras/fatfs/ff.h @@ -1,8 +1,8 @@ /*----------------------------------------------------------------------------/ -/ FatFs - Generic FAT file system module R0.12b / +/ FatFs - Generic FAT file system module R0.12c / /-----------------------------------------------------------------------------/ / -/ Copyright (C) 2016, ChaN, all right reserved. +/ Copyright (C) 2017, ChaN, all right reserved. / / FatFs module is an open source software. Redistribution and use of FatFs in / source and binary forms, with or without modification, are permitted provided @@ -19,7 +19,7 @@ #ifndef _FATFS -#define _FATFS 68020 /* Revision ID */ +#define _FATFS 68300 /* Revision ID */ #ifdef __cplusplus extern "C" { @@ -42,13 +42,6 @@ typedef struct { BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */ } PARTITION; extern PARTITION VolToPart[]; /* Volume - Partition resolution table */ -#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */ -#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */ - -#else /* Single partition configuration */ -#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */ -#define LD2PT(vol) 0 /* Find first valid partition or in SFD */ - #endif @@ -140,14 +133,15 @@ typedef struct { FATFS* fs; /* Pointer to the owner file system object */ WORD id; /* Owner file system mount ID */ BYTE attr; /* Object attribute */ - BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:got flagmented, b2:sub-directory stretched) */ + BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */ DWORD sclust; /* Object start cluster (0:no cluster or root directory) */ FSIZE_t objsize; /* Object size (valid when sclust != 0) */ #if _FS_EXFAT - DWORD n_cont; /* Size of coutiguous part, clusters - 1 (valid when stat == 3) */ + DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */ + DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */ DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */ DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */ - DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0) */ + DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */ #endif #if _FS_LOCK != 0 UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */ @@ -163,7 +157,7 @@ typedef struct { BYTE flag; /* File status flags */ BYTE err; /* Abort flag (error code) */ FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */ - DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */ + DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */ DWORD sect; /* Sector number appearing in buf[] (0:invalid) */ #if !_FS_READONLY DWORD dir_sect; /* Sector number containing the directory entry */ @@ -185,7 +179,7 @@ typedef struct { _FDID obj; /* Object identifier */ DWORD dptr; /* Current read/write offset */ DWORD clust; /* Current cluster */ - DWORD sect; /* Current sector */ + DWORD sect; /* Current sector (0:Read operation has terminated) */ BYTE* dir; /* Pointer to the directory item in the win[] */ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */ #if _USE_LFN != 0 @@ -285,6 +279,7 @@ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the fil #define f_size(fp) ((fp)->obj.objsize) #define f_rewind(fp) f_lseek((fp), 0) #define f_rewinddir(dp) f_readdir((dp), 0) +#define f_rmdir(path) f_unlink(path) #ifndef EOF #define EOF (-1) diff --git a/extras/fatfs/ffconf.h b/extras/fatfs/ffconf.h index 7962e2a..a97a6ae 100644 --- a/extras/fatfs/ffconf.h +++ b/extras/fatfs/ffconf.h @@ -1,7 +1,7 @@ /*---------------------------------------------------------------------------/ / FatFs - FAT file system module configuration file /---------------------------------------------------------------------------*/ -#define _FFCONF 68020 /* Revision ID */ +#define _FFCONF 68300 /* Revision ID */ /*---------------------------------------------------------------------------/ / Function Configurations diff --git a/extras/hd44780/hd44780.c b/extras/hd44780/hd44780.c index b44f65a..d7bbc0a 100644 --- a/extras/hd44780/hd44780.c +++ b/extras/hd44780/hd44780.c @@ -60,8 +60,8 @@ static void write_nibble(const hd44780_t *lcd, uint8_t b, bool rs) | (rs ? 1 << lcd->pins.rs : 0) | (lcd->backlight ? 1 << lcd->pins.bl : 0); - pcf8574_port_write(lcd->addr, data | (1 << lcd->pins.e)); - pcf8574_port_write(lcd->addr, data); + pcf8574_port_write(&lcd->i2c_dev, data | (1 << lcd->pins.e)); + pcf8574_port_write(&lcd->i2c_dev, data); #else gpio_write(lcd->pins.d7, (b >> 3) & 1); gpio_write(lcd->pins.d6, (b >> 2) & 1); @@ -164,7 +164,7 @@ void hd44780_set_backlight(hd44780_t *lcd, bool on) return; #if (HD44780_I2C) - pcf8574_gpio_write(lcd->addr, lcd->pins.bl, on); + pcf8574_gpio_write(&lcd->i2c_dev, lcd->pins.bl, on); #else gpio_write(lcd->pins.bl, on); #endif diff --git a/extras/hd44780/hd44780.h b/extras/hd44780/hd44780.h index a00302b..c5152de 100644 --- a/extras/hd44780/hd44780.h +++ b/extras/hd44780/hd44780.h @@ -12,7 +12,10 @@ #include #ifndef HD44780_I2C -#define HD44780_I2C 0 +#define HD44780_I2C 1 +#endif +#if (HD44780_I2C) +#include #endif #ifdef __cplusplus @@ -36,7 +39,9 @@ typedef enum */ typedef struct { - uint8_t addr; //!< PCF8574 address (0b0100) +#if (HD44780_I2C) + i2c_dev_t i2c_dev; //!< PCF8574 device settings (0b0100) +#endif struct { uint8_t rs; //!< gpio/register bit used for RS pin diff --git a/extras/hmc5883l/hmc5883l.c b/extras/hmc5883l/hmc5883l.c index 28d9cf7..e970fa2 100644 --- a/extras/hmc5883l/hmc5883l.c +++ b/extras/hmc5883l/hmc5883l.c @@ -6,10 +6,8 @@ * BSD Licensed as described in the file LICENSE */ #include "hmc5883l.h" -#include #include -#define ADDR 0x1e #define REG_CR_A 0x00 #define REG_CR_B 0x01 @@ -38,6 +36,8 @@ #define MEASUREMENT_TIMEOUT 6000 +#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len)) + static const float gain_values [] = { [HMC5883L_GAIN_1370] = 0.73, [HMC5883L_GAIN_1090] = 0.92, @@ -52,119 +52,120 @@ static const float gain_values [] = { static float current_gain; static hmc5883l_operating_mode_t current_mode; -static inline void write_register(uint8_t reg, uint8_t val) +static inline void write_register(i2c_dev_t* dev, uint8_t reg, uint8_t val) { - uint8_t buf[2] = { reg, val }; - i2c_slave_write(ADDR, buf, 2); + i2c_slave_write(dev->bus, dev->addr, ®, &val, 1); } -static inline uint8_t read_register(uint8_t reg) +static inline uint8_t read_register(i2c_dev_t* dev, uint8_t reg) { uint8_t res; - i2c_slave_read(ADDR, reg, &res, 1); + i2c_slave_read(dev->bus, dev->addr, ®, &res, 1); return res; } -static inline void update_register(uint8_t reg, uint8_t mask, uint8_t val) +static inline void update_register(i2c_dev_t* dev, uint8_t reg, uint8_t mask, uint8_t val) { - write_register(reg, (read_register(reg) & mask) | val); + write_register(dev, reg, (read_register(dev, reg) & mask) | val); } -bool hmc5883l_init() +bool hmc5883l_init(i2c_dev_t* dev) { - if (hmc5883l_get_id() != HMC5883L_ID) + if (hmc5883l_get_id(dev) != HMC5883L_ID) return false; - current_gain = gain_values[hmc5883l_get_gain()]; - current_mode = hmc5883l_get_operating_mode(); + current_gain = gain_values[hmc5883l_get_gain(dev)]; + current_mode = hmc5883l_get_operating_mode(dev); return true; } -uint32_t hmc5883l_get_id() +uint32_t hmc5883l_get_id(i2c_dev_t* dev) { uint32_t res = 0; - i2c_slave_read(ADDR, REG_ID_A, (uint8_t *)&res, 3); + uint8_t reg = REG_ID_A; + i2c_slave_read(dev->bus, dev->addr, ®, (uint8_t *)&res, 3); return res; } -hmc5883l_operating_mode_t hmc5883l_get_operating_mode() +hmc5883l_operating_mode_t hmc5883l_get_operating_mode(i2c_dev_t* dev) { - uint8_t res = read_register(REG_MODE) & MASK_MD; + uint8_t res = read_register(dev, REG_MODE) & MASK_MD; return res == 0 ? HMC5883L_MODE_CONTINUOUS : HMC5883L_MODE_SINGLE; } -void hmc5883l_set_operating_mode(hmc5883l_operating_mode_t mode) +void hmc5883l_set_operating_mode(i2c_dev_t* dev, hmc5883l_operating_mode_t mode) { - write_register(REG_MODE, mode); + write_register(dev, REG_MODE, mode); current_mode = mode; } -hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged() +hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged(i2c_dev_t* dev) { - return (read_register(REG_CR_A) & MASK_MA) >> BIT_MA; + return (read_register(dev, REG_CR_A) & MASK_MA) >> BIT_MA; } -void hmc5883l_set_samples_averaged(hmc5883l_samples_averaged_t samples) +void hmc5883l_set_samples_averaged(i2c_dev_t* dev, hmc5883l_samples_averaged_t samples) { - update_register(REG_CR_A, MASK_MA, samples << BIT_MA); + update_register(dev, REG_CR_A, MASK_MA, samples << BIT_MA); } -hmc5883l_data_rate_t hmc5883l_get_data_rate() +hmc5883l_data_rate_t hmc5883l_get_data_rate(i2c_dev_t* dev) { - return (read_register(REG_CR_A) & MASK_DO) >> BIT_DO; + return (read_register(dev, REG_CR_A) & MASK_DO) >> BIT_DO; } -void hmc5883l_set_data_rate(hmc5883l_data_rate_t rate) +void hmc5883l_set_data_rate(i2c_dev_t* dev, hmc5883l_data_rate_t rate) { - update_register(REG_CR_A, MASK_DO, rate << BIT_DO); + update_register(dev, REG_CR_A, MASK_DO, rate << BIT_DO); } -hmc5883l_bias_t hmc5883l_get_bias() +hmc5883l_bias_t hmc5883l_get_bias(i2c_dev_t* dev) { - return read_register(REG_CR_A) & MASK_MS; + return read_register(dev, REG_CR_A) & MASK_MS; } -void hmc5883l_set_bias(hmc5883l_bias_t bias) +void hmc5883l_set_bias(i2c_dev_t* dev, hmc5883l_bias_t bias) { - update_register(REG_CR_A, MASK_MS, bias); + update_register(dev, REG_CR_A, MASK_MS, bias); } -hmc5883l_gain_t hmc5883l_get_gain() +hmc5883l_gain_t hmc5883l_get_gain(i2c_dev_t* dev) { - return read_register(REG_CR_B) >> BIT_GN; + return read_register(dev, REG_CR_B) >> BIT_GN; } -void hmc5883l_set_gain(hmc5883l_gain_t gain) +void hmc5883l_set_gain(i2c_dev_t* dev, hmc5883l_gain_t gain) { - write_register(REG_CR_B, gain << BIT_GN); + write_register(dev, REG_CR_B, gain << BIT_GN); current_gain = gain_values[gain]; } -bool hmc5883l_data_is_locked() +bool hmc5883l_data_is_locked(i2c_dev_t* dev) { - return read_register(REG_STAT) & MASK_DL; + return read_register(dev, REG_STAT) & MASK_DL; } -bool hmc5883l_data_is_ready() +bool hmc5883l_data_is_ready(i2c_dev_t* dev) { - return read_register(REG_STAT) & MASK_DR; + return read_register(dev, REG_STAT) & MASK_DR; } -bool hmc5883l_get_raw_data(hmc5883l_raw_data_t *data) +bool hmc5883l_get_raw_data(i2c_dev_t* dev, hmc5883l_raw_data_t *data) { if (current_mode == HMC5883L_MODE_SINGLE) { // overwrite mode register for measurement - hmc5883l_set_operating_mode(current_mode); + hmc5883l_set_operating_mode(dev, current_mode); // wait for data - uint32_t timeout = sdk_system_get_time() + MEASUREMENT_TIMEOUT; - while (!hmc5883l_data_is_ready()) + uint32_t start = sdk_system_get_time(); + while (!hmc5883l_data_is_ready(dev)) { - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, MEASUREMENT_TIMEOUT)) return false; } } uint8_t buf[6]; - i2c_slave_read(ADDR, REG_DX_H, buf, 6); + uint8_t reg = REG_DX_H; + i2c_slave_read(dev->bus, dev->addr, ®, buf, 6); data->x = ((int16_t)buf[REG_DX_H - REG_DX_H] << 8) | buf[REG_DX_L - REG_DX_H]; data->y = ((int16_t)buf[REG_DY_H - REG_DX_H] << 8) | buf[REG_DY_L - REG_DX_H]; data->z = ((int16_t)buf[REG_DZ_H - REG_DX_H] << 8) | buf[REG_DZ_L - REG_DX_H]; @@ -178,11 +179,11 @@ void hmc5883l_raw_to_mg(const hmc5883l_raw_data_t *raw, hmc5883l_data_t *mg) mg->z = raw->z * current_gain; } -bool hmc5883l_get_data(hmc5883l_data_t *data) +bool hmc5883l_get_data(i2c_dev_t* dev, hmc5883l_data_t *data) { hmc5883l_raw_data_t raw; - if (!hmc5883l_get_raw_data(&raw)) + if (!hmc5883l_get_raw_data(dev, &raw)) return false; hmc5883l_raw_to_mg(&raw, data); return true; diff --git a/extras/hmc5883l/hmc5883l.h b/extras/hmc5883l/hmc5883l.h index 720a385..5958e61 100644 --- a/extras/hmc5883l/hmc5883l.h +++ b/extras/hmc5883l/hmc5883l.h @@ -10,12 +10,15 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif +#define HMC5883L_ADDR 0x1e + #define HMC5883L_ID 0x00333448 // "H43" /** @@ -101,82 +104,82 @@ typedef struct * \brief Init device * \return false if error occured */ -bool hmc5883l_init(); +bool hmc5883l_init(i2c_dev_t* dev); /** * \brief Get device ID * Always returns 0x00333448 if IC functioning properly. * \return Device ID */ -uint32_t hmc5883l_get_id(); +uint32_t hmc5883l_get_id(i2c_dev_t* dev); /** * \brief Get operating mode * \return Measurement mode */ -hmc5883l_operating_mode_t hmc5883l_get_operating_mode(); +hmc5883l_operating_mode_t hmc5883l_get_operating_mode(i2c_dev_t* dev); /** * \brief Set operating mode * \param mode Measurement mode */ -void hmc5883l_set_operating_mode(hmc5883l_operating_mode_t mode); +void hmc5883l_set_operating_mode(i2c_dev_t* dev, hmc5883l_operating_mode_t mode); /** * \brief Get number of samples averaged per measurement output * \return Number of samples */ -hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged(); +hmc5883l_samples_averaged_t hmc5883l_get_samples_averaged(i2c_dev_t* dev); /** * \brief Set number of samples averaged per measurement output * \param samples Number of samples */ -void hmc5883l_set_samples_averaged(hmc5883l_samples_averaged_t samples); +void hmc5883l_set_samples_averaged(i2c_dev_t* dev, hmc5883l_samples_averaged_t samples); /** * \brief Get data output rate in continuous measurement mode * \return Data output rate */ -hmc5883l_data_rate_t hmc5883l_get_data_rate(); +hmc5883l_data_rate_t hmc5883l_get_data_rate(i2c_dev_t* dev); /** * \brief Set data output rate in continuous measurement mode * \param rate Data output rate */ -void hmc5883l_set_data_rate(hmc5883l_data_rate_t rate); +void hmc5883l_set_data_rate(i2c_dev_t* dev, hmc5883l_data_rate_t rate); /** * \brief Get measurement mode (bias of the axes) * See datasheet for self test description * \return Bias */ -hmc5883l_bias_t hmc5883l_get_bias(); +hmc5883l_bias_t hmc5883l_get_bias(i2c_dev_t* dev); /** * \brief Set measurement mode (bias of the axes) * See datasheet for self test description * \param bias Bias */ -void hmc5883l_set_bias(hmc5883l_bias_t bias); +void hmc5883l_set_bias(i2c_dev_t* dev, hmc5883l_bias_t bias); /** * \brief Get device gain * \return Current gain */ -hmc5883l_gain_t hmc5883l_get_gain(); +hmc5883l_gain_t hmc5883l_get_gain(i2c_dev_t* dev); /** * \brief Set device gain * \param gain Gain */ -void hmc5883l_set_gain(hmc5883l_gain_t gain); +void hmc5883l_set_gain(i2c_dev_t* dev, hmc5883l_gain_t gain); /** * \brief Get data state * \return true when data is written to all six data registers */ -bool hmc5883l_data_is_ready(); +bool hmc5883l_data_is_ready(i2c_dev_t* dev); /** * \brief Get lock state. @@ -188,14 +191,14 @@ bool hmc5883l_data_is_ready(); * 4. power is reset. * \return true when data registers is locked */ -bool hmc5883l_data_is_locked(); +bool hmc5883l_data_is_locked(i2c_dev_t* dev); /** * \brief Get raw magnetic data * \param data Pointer to the struct to write raw data * \return false if error occured in single measurement mode, always true in continuous mode */ -bool hmc5883l_get_raw_data(hmc5883l_raw_data_t *data); +bool hmc5883l_get_raw_data(i2c_dev_t* dev, hmc5883l_raw_data_t *data); /** * \brief Convert raw magnetic data to milligausses @@ -209,7 +212,7 @@ void hmc5883l_raw_to_mg(const hmc5883l_raw_data_t *raw, hmc5883l_data_t *mg); * \param data Pointer to the struct to write data * \return false if error occured in single measurement mode, always true in continuous mode */ -bool hmc5883l_get_data(hmc5883l_data_t *data); +bool hmc5883l_get_data(i2c_dev_t* dev, hmc5883l_data_t *data); #ifdef __cplusplus } diff --git a/extras/httpd/httpd.c b/extras/httpd/httpd.c index f647ca6..fcbc290 100644 --- a/extras/httpd/httpd.c +++ b/extras/httpd/httpd.c @@ -139,7 +139,7 @@ /** Set this to 1 on platforms where strnstr is not available */ #ifndef LWIP_HTTPD_STRNSTR_PRIVATE -#define LWIP_HTTPD_STRNSTR_PRIVATE 1 +#define LWIP_HTTPD_STRNSTR_PRIVATE 0 #endif /** 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. */ static void -httpd_init_addr(ip_addr_t *local_addr) +httpd_init_addr(const ip_addr_t *local_addr) { struct tcp_pcb *pcb; err_t err; diff --git a/extras/httpd/httpd.h b/extras/httpd/httpd.h index 59b0095..1214054 100644 --- a/extras/httpd/httpd.h +++ b/extras/httpd/httpd.h @@ -231,7 +231,7 @@ void httpd_post_data_recved(void *connection, u16_t recved_len); #endif /* LWIP_HTTPD_SUPPORT_POST */ -enum { +typedef enum { WS_TEXT_MODE = 0x01, WS_BIN_MODE = 0x02, } WS_MODE; diff --git a/extras/i2c/README.md b/extras/i2c/README.md index 7ab90f6..cac119d 100644 --- a/extras/i2c/README.md +++ b/extras/i2c/README.md @@ -2,18 +2,8 @@ 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]. -### Adding to your project - -Add the driver to your project as a submodule rather than cloning it: - -```` -% git submodule add https://github.com/kanflo/esp-open-rtos-driver-i2c.git i2c -```` -The esp-open-rtos makefile-fu will make sure the driver is built. - ### Usage - ```` #include @@ -23,18 +13,23 @@ The esp-open-rtos makefile-fu will make sure the driver is built. uint8_t slave_addr = 0x20; uint8_t reg_addr = 0x1f; uint8_t reg_data; -uint8_t data[] = {reg_addr, 0xc8}; i2c_init(SCL_PIN, SDA_PIN); -// Write data to slave -bool success = i2c_slave_write(slave_addr, data, sizeof(data)); +// Write 1 byte to slave register +int err = i2c_slave_write(slave_addr, ®_addr, &data, 1); +if (err != 0) +{ + // do something with error +} // Issue write to slave, sending reg_addr, followed by reading 1 byte -success = i2c_slave_read(slave_addr, ®_addr, reg_data, 1); +err = i2c_slave_read(slave_addr, ®_addr, ®_data, 1); ```` +For details please see `extras/i2c/i2c.h`. + The driver is released under the MIT license. [1] https://en.wikipedia.org/wiki/I²C#Example_of_bit-banging_the_I.C2.B2C_Master_protocol \ No newline at end of file diff --git a/extras/i2c/i2c.c b/extras/i2c/i2c.c index 2d31e8e..034bcdc 100644 --- a/extras/i2c/i2c.c +++ b/extras/i2c/i2c.c @@ -1,18 +1,18 @@ -/* +/* * The MIT License (MIT) - * + * * Copyright (c) 2015 Johan Kanflo (github.com/kanflo) - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -24,217 +24,306 @@ #include #include // sdk_os_delay_us +#include #include "i2c.h" +//#define I2C_DEBUG true -// 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 ~100kbit/s -#define CLK_HALF_PERIOD_US (1) +#ifdef I2C_DEBUG +#define debug(fmt, ...) printf("%s: " fmt "\n", "I2C", ## __VA_ARGS__) +#else +#define debug(fmt, ...) +#endif #define CLK_STRETCH (10) -static bool started; -static uint8_t g_scl_pin; -static uint8_t g_sda_pin; +static uint8_t freq ; // Store CPU frequency for optimisation speed in delay function ( Warning: Don't change CPU frequency during a transaction) +static i2c_bus_description_t i2c_bus[MAX_I2C_BUS]; -void i2c_init(uint8_t scl_pin, uint8_t sda_pin) +inline bool i2c_status(uint8_t bus) { - started = false; - g_scl_pin = scl_pin; - g_sda_pin = sda_pin; - - // Just to prevent these pins floating too much if not connected. - gpio_set_pullup(g_scl_pin, 1, 1); - gpio_set_pullup(g_sda_pin, 1, 1); - - gpio_enable(g_scl_pin, GPIO_OUT_OPEN_DRAIN); - gpio_enable(g_sda_pin, GPIO_OUT_OPEN_DRAIN); - - // I2C bus idle state. - gpio_write(g_scl_pin, 1); - gpio_write(g_sda_pin, 1); + return i2c_bus[bus].started; } -static inline void i2c_delay(void) +void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq) { - sdk_os_delay_us(CLK_HALF_PERIOD_US); + i2c_bus[bus].started = false; + i2c_bus[bus].flag = false ; + i2c_bus[bus].g_scl_pin = scl_pin; + i2c_bus[bus].g_sda_pin = sda_pin; + i2c_bus[bus].frequency = freq ; + + // 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_sda_pin, 1, 1); + + gpio_enable(i2c_bus[bus].g_scl_pin, GPIO_OUT_OPEN_DRAIN); + gpio_enable(i2c_bus[bus].g_sda_pin, GPIO_OUT_OPEN_DRAIN); + + // I2C bus idle state. + gpio_write(i2c_bus[bus].g_scl_pin, 1); + gpio_write(i2c_bus[bus].g_sda_pin, 1); + + // Prevent user, if frequency is high + if (sdk_system_get_cpu_freq() == SYS_CPU_80MHZ) + if (i2c_freq_array[i2c_bus[bus].frequency][1] == 1) + debug("Max frequency is 320Khz at 80MHz"); + +} + +void i2c_frequency(uint8_t bus, i2c_freq_t freq) +{ + i2c_bus[bus].frequency = freq ; +} + +static inline void i2c_delay(uint8_t bus) +{ + uint32_t delay; + if (freq == SYS_CPU_160MHZ) + { + delay = i2c_freq_array[i2c_bus[bus].frequency][0]; + __asm volatile ( + "1: addi %0, %0, -1" "\n" + "bnez %0, 1b" "\n" + :: "a" (delay)); + } + else + { + delay = i2c_freq_array[i2c_bus[bus].frequency][1]; + __asm volatile ( + "1: addi %0, %0, -1" "\n" + "bnez %0, 1b" "\n" + :: "a" (delay)); + } } // Set SCL as input, allowing it to float high, and return current // level of line, 0 or 1 -static inline bool read_scl(void) +static inline bool read_scl(uint8_t bus) { - gpio_write(g_scl_pin, 1); - return gpio_read(g_scl_pin); // Clock high, valid ACK + gpio_write(i2c_bus[bus].g_scl_pin, 1); + return gpio_read(i2c_bus[bus].g_scl_pin); // Clock high, valid ACK } // Set SDA as input, allowing it to float high, and return current // level of line, 0 or 1 -static inline bool read_sda(void) +static inline bool read_sda(uint8_t bus) { - gpio_write(g_sda_pin, 1); + gpio_write(i2c_bus[bus].g_sda_pin, 1); // TODO: Without this delay we get arbitration lost in i2c_stop - i2c_delay(); - return gpio_read(g_sda_pin); // Clock high, valid ACK + i2c_delay(bus); + return gpio_read(i2c_bus[bus].g_sda_pin); // Clock high, valid ACK } // Actively drive SCL signal low -static inline void clear_scl(void) +static inline void clear_scl(uint8_t bus) { - gpio_write(g_scl_pin, 0); + gpio_write(i2c_bus[bus].g_scl_pin, 0); } // Actively drive SDA signal low -static inline void clear_sda(void) +static inline void clear_sda(uint8_t bus) { - gpio_write(g_sda_pin, 0); + gpio_write(i2c_bus[bus].g_sda_pin, 0); } // Output start condition -void i2c_start(void) +void i2c_start(uint8_t bus) { - uint32_t clk_stretch = CLK_STRETCH; - if (started) { // if started, do a restart cond + freq = sdk_system_get_cpu_freq(); + if (i2c_bus[bus].started) { // if started, do a restart cond // Set SDA to 1 - (void) read_sda(); - i2c_delay(); - while (read_scl() == 0 && clk_stretch--) ; + (void) read_sda(bus); + i2c_delay(bus); + uint32_t clk_stretch = CLK_STRETCH; + while (read_scl(bus) == 0 && clk_stretch--) ; // Repeated start setup time, minimum 4.7us - i2c_delay(); + i2c_delay(bus); } - if (read_sda() == 0) { - printf("I2C: arbitration lost in i2c_start\n"); + i2c_bus[bus].started = true; + if (read_sda(bus) == 0) { + debug("arbitration lost in i2c_start from bus %u",bus); } // SCL is high, set SDA from 1 to 0. - clear_sda(); - i2c_delay(); - clear_scl(); - started = true; + clear_sda(bus); + i2c_delay(bus); + clear_scl(bus); } // Output stop condition -void i2c_stop(void) +bool i2c_stop(uint8_t bus) { uint32_t clk_stretch = CLK_STRETCH; // Set SDA to 0 - clear_sda(); - i2c_delay(); + clear_sda(bus); + i2c_delay(bus); // Clock stretching - while (read_scl() == 0 && clk_stretch--) ; + while (read_scl(bus) == 0 && clk_stretch--) ; // Stop bit setup time, minimum 4us - i2c_delay(); + i2c_delay(bus); // SCL is high, set SDA from 0 to 1 - if (read_sda() == 0) { - printf("I2C: arbitration lost in i2c_stop\n"); + if (read_sda(bus) == 0) { + debug("arbitration lost in i2c_stop from bus %u",bus); } - i2c_delay(); - started = false; + i2c_delay(bus); + if (!i2c_bus[bus].started) { + debug("bus %u link was break!",bus); + return false ; //If bus was stop in other way, the current transmission Failed + } + i2c_bus[bus].started = false; + return true; } // Write a bit to I2C bus -static void i2c_write_bit(bool bit) +static void i2c_write_bit(uint8_t bus, bool bit) { uint32_t clk_stretch = CLK_STRETCH; if (bit) { - (void) read_sda(); + (void) read_sda(bus); } else { - clear_sda(); + clear_sda(bus); } - i2c_delay(); + i2c_delay(bus); // Clock stretching - while (read_scl() == 0 && clk_stretch--) ; + while (read_scl(bus) == 0 && clk_stretch--) ; // SCL is high, now data is valid // If SDA is high, check that nobody else is driving SDA - if (bit && read_sda() == 0) { - printf("I2C: arbitration lost in i2c_write_bit\n"); + if (bit && read_sda(bus) == 0) { + debug("arbitration lost in i2c_write_bit from bus %u",bus); } - i2c_delay(); - clear_scl(); + i2c_delay(bus); + clear_scl(bus); } // Read a bit from I2C bus -static bool i2c_read_bit(void) +static bool i2c_read_bit(uint8_t bus) { uint32_t clk_stretch = CLK_STRETCH; bool bit; // Let the slave drive data - (void) read_sda(); - i2c_delay(); + (void) read_sda(bus); + i2c_delay(bus); // Clock stretching - while (read_scl() == 0 && clk_stretch--) ; + while (read_scl(bus) == 0 && clk_stretch--) ; // SCL is high, now data is valid - bit = read_sda(); - i2c_delay(); - clear_scl(); + bit = read_sda(bus); + i2c_delay(bus); + clear_scl(bus); return bit; } -bool i2c_write(uint8_t byte) +bool i2c_write(uint8_t bus, uint8_t byte) { bool nack; uint8_t bit; for (bit = 0; bit < 8; bit++) { - i2c_write_bit((byte & 0x80) != 0); + i2c_write_bit(bus,(byte & 0x80) != 0); byte <<= 1; } - nack = i2c_read_bit(); + nack = i2c_read_bit(bus); return !nack; } -uint8_t i2c_read(bool ack) +uint8_t i2c_read(uint8_t bus, bool ack) { uint8_t byte = 0; uint8_t bit; for (bit = 0; bit < 8; bit++) { - byte = (byte << 1) | i2c_read_bit(); + byte = ((byte << 1)) | (i2c_read_bit(bus)); } - i2c_write_bit(ack); + i2c_write_bit(bus,ack); return byte; } -bool i2c_slave_write(uint8_t slave_addr, uint8_t *data, uint8_t len) +void i2c_force_bus(uint8_t bus, bool state) { - bool success = false; - do { - i2c_start(); - if (!i2c_write(slave_addr << 1)) - break; - while (len--) { - if (!i2c_write(*data++)) - break; - } - i2c_stop(); - success = true; - } while(0); - return success; + i2c_bus[bus].force = state ; } -bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len) +static int i2c_bus_test(uint8_t bus) { - bool success = false; - do { - i2c_start(); - if (!i2c_write(slave_addr << 1)) { - break; - } - i2c_write(data); - i2c_stop(); - i2c_start(); - if (!i2c_write(slave_addr << 1 | 1)) { // Slave address + read - break; - } - while(len) { - *buf = i2c_read(len == 1); - buf++; - len--; - } - success = true; - } while(0); - i2c_stop(); - if (!success) { - printf("I2C: write error\n"); + taskENTER_CRITICAL(); // To prevent task swaping after checking flag and before set it! + bool status = i2c_bus[bus].flag ; // get current status + if(i2c_bus[bus].force) + { + i2c_bus[bus].flag = true ; // force bus on + taskEXIT_CRITICAL(); + if(status) + i2c_stop(bus); //Bus was busy, stop it. } - return success; + else + { + if (status) + { + taskEXIT_CRITICAL(); + debug("busy"); + taskYIELD(); // If bus busy, change task to try finish last com. + return -EBUSY ; // If bus busy, inform user + } + else + { + i2c_bus[bus].flag = true ; // Set Bus busy + taskEXIT_CRITICAL(); + } + } + return 0 ; +} + +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)) + return -EBUSY ; + i2c_start(bus); + if (!i2c_write(bus, slave_addr << 1)) + goto error; + if(data != NULL) + if (!i2c_write(bus,*data)) + goto error; + while (len--) { + if (!i2c_write(bus,*buf++)) + goto error; + } + if (!i2c_stop(bus)) + goto error; + i2c_bus[bus].flag = false ; // Bus free + return 0; + + error: + debug("Bus %u Write Error",bus); + i2c_stop(bus); + i2c_bus[bus].flag = false ; // Bus free + return -EIO; +} + +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)) + return -EBUSY ; + if(data != NULL) { + i2c_start(bus); + if (!i2c_write(bus,slave_addr << 1)) + goto error; + if (!i2c_write(bus,*data)) + goto error; + if (!i2c_stop(bus)) + goto error; + } + i2c_start(bus); + if (!i2c_write(bus,slave_addr << 1 | 1)) // Slave address + read + goto error; + while(len) { + *buf = i2c_read(bus,len == 1); + buf++; + len--; + } + if (!i2c_stop(bus)) + goto error; + i2c_bus[bus].flag = false ; // Bus free + return 0; + + error: + debug("Read Error"); + i2c_stop(bus); + i2c_bus[bus].flag = false ; // Bus free + return -EIO; } diff --git a/extras/i2c/i2c.h b/extras/i2c/i2c.h index bfb3811..c2e31cd 100644 --- a/extras/i2c/i2c.h +++ b/extras/i2c/i2c.h @@ -1,18 +1,18 @@ -/* +/* * The MIT License (MIT) - * + * * Copyright (c) 2015 Johan Kanflo (github.com/kanflo) - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -27,31 +27,148 @@ #include #include +#include +#include +#include #ifdef __cplusplus extern "C" { #endif -// Init bitbanging I2C driver on given pins -void i2c_init(uint8_t scl_pin, uint8_t sda_pin); -// Write a byte to I2C bus. Return true if slave acked. -bool i2c_write(uint8_t byte); +/* + * Define i2c bus max number + */ +#define MAX_I2C_BUS 2 -// Read a byte from I2C bus. Return true if slave acked. -uint8_t i2c_read(bool ack); -// Write 'len' bytes from 'buf' to slave. Return true if slave acked. -bool i2c_slave_write(uint8_t slave_addr, uint8_t *buf, uint8_t len); +/* + * following array contain value for different frequency + * Warning : 1 is minimal, that mean at 80MHz clock, frequency max is 320kHz + * Array format is { {160MHz, 80MHz} , {160MHz, 80MHz} , ... } + */ +#define NB_FREQ_AVAILABLE 4 -// Issue a read operation and send 'data', followed by reading 'len' bytes -// from slave into 'buf'. Return true if slave acked. -bool i2c_slave_read(uint8_t slave_addr, uint8_t data, uint8_t *buf, uint32_t len); + typedef enum { + I2C_FREQ_80K = 0, + I2C_FREQ_100K, + I2C_FREQ_400K, + I2C_FREQ_500K, +} i2c_freq_t; -// Send start and stop conditions. Only needed when implementing protocols for -// devices where the i2c_slave_[read|write] functions above are of no use. -void i2c_start(void); -void i2c_stop(void); +const static uint8_t i2c_freq_array[NB_FREQ_AVAILABLE][2] = { {255,35}, {100,20}, {10,1}, {6,1} } ; + +/** + * Device descriptor + */ +typedef struct i2c_dev { + uint8_t bus ; + uint8_t addr ; +} i2c_dev_t ; + +/** + * 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 + * @param bus Bus i2c selection + * @param scl_pin SCL pin for I2C + * @param sda_pin SDA pin for I2C + * @param freq frequency of bus (ex : I2C_FREQ_400K) + */ +void i2c_init(uint8_t bus, uint8_t scl_pin, uint8_t sda_pin, i2c_freq_t freq); + +/** + * Change bus frequency + * @param bus Bus i2c selection + * @param freq frequency of bus (ex : I2C_FREQ_400K) + */ +void i2c_frequency(uint8_t bus, i2c_freq_t freq); + +/** + * Write a byte to I2C bus. + * @param bus Bus i2c selection + * @param byte Pointer to device descriptor + * @return true if slave acked + */ +bool i2c_write(uint8_t bus, uint8_t byte); + +/** + * Read a byte from I2C bus. + * @param bus Bus i2c selection + * @param ack Set Ack for slave (false: Ack // true: NoAck) + * @return byte read from slave. + */ +uint8_t i2c_read(uint8_t bus, bool ack); + +/** + * Send start or restart condition + * @param bus Bus i2c selection + */ +void i2c_start(uint8_t bus); + +/** + * Send stop condition + * @param bus Bus i2c selection + * @return false if link was broken + */ +bool i2c_stop(uint8_t bus); + +/** + * get status from I2C bus. + * @param bus Bus i2c selection + * @return true if busy. + */ +bool i2c_status(uint8_t bus); + +//Level 1 API (Don't need functions above) + +/** + * This function will allow you to force a transmission I2C, cancel current transmission. + * Warning: Use with precaution. Don't use it if you can avoid it. Usefull for priority transmission. + * @param bus Bus i2c selection + * @param state Force the next I2C transmission if true (Use with precaution) + */ +void i2c_force_bus(uint8_t bus, bool state); + +/** + * Write 'len' bytes from 'buf' to slave at 'data' register adress . + * @param bus Bus i2c selection + * @param slave_addr slave device address + * @param data Pointer to register address to send if non-null + * @param buf Pointer to data buffer + * @param len Number of byte to send + * @return Non-Zero if error occured + */ +int i2c_slave_write(uint8_t bus, uint8_t slave_addr, const uint8_t *data, const uint8_t *buf, uint32_t len); + +/** + * Issue a send operation of 'data' register adress, followed by reading 'len' bytes + * from slave into 'buf'. + * @param bus Bus i2c selection + * @param slave_addr slave device address + * @param data Pointer to register address to send if non-null + * @param buf Pointer to data buffer + * @param len Number of byte to read + * @return Non-Zero if error occured + */ +int i2c_slave_read(uint8_t bus, uint8_t slave_addr, const uint8_t *data, uint8_t *buf, uint32_t len); #ifdef __cplusplus } diff --git a/extras/i2s_dma/i2s_dma.c b/extras/i2s_dma/i2s_dma.c index 442cdf3..9609f1b 100644 --- a/extras/i2s_dma/i2s_dma.c +++ b/extras/i2s_dma/i2s_dma.c @@ -62,7 +62,7 @@ void sdk_rom_i2c_writeReg_Mask(uint32_t block, uint32_t host_id, 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 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); 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); SLC.INT_CLEAR = 0xFFFFFFFF; _xt_isr_unmask(1<> 8) & 0xFF)) - goto error; - if (!i2c_write(value & 0xFF)) - goto error; - i2c_stop(); - debug("Data write to %02X : %02X+%04X\n",addr,reg,value); - - return 0 ; - - error: - debug("Error while xmitting I2C slave\n"); - i2c_stop(); - return -EIO; + uint8_t d[2] = { 0 , 0 }; + d[1] = value & 0x00FF; + d[0] = (value >> 8) & 0x00FF; + debug("Data write to bus %u at %02X : %02X+%04X\n",dev->bus, dev->addr, reg, value); + return i2c_slave_write(dev->bus, dev->addr, ®, d, sizeof(d)); } -static int _wireReadRegister(uint8_t addr, uint8_t reg, uint16_t *value) +static int _wireReadRegister(const i2c_dev_t* dev, uint8_t reg, uint16_t *value) { - uint8_t tampon[2] = { 0 } ; - - i2c_start(); - if (!i2c_write(addr<<1)) // adress + W - goto error; - if (!i2c_write(reg)) - goto error; - i2c_stop(); - i2c_start(); // restart condition - if (!i2c_write((addr<<1) | 1)) // adress + R - goto error; - tampon[1] = i2c_read(0); - tampon[0] = i2c_read(1); - i2c_stop(); - *value = tampon[1]<<8 | tampon[0] ; - debug("Data read from %02X: %02X+%04X\n",addr,reg,*value); - - return 0; - - error: - debug("Error while xmitting I2C slave\n"); - i2c_stop(); - return -EIO; + uint8_t d[] = {0, 0}; + int error = i2c_slave_read(dev->bus, dev->addr, ®, d, sizeof(d)) + debug("Data read from bus %u at %02X: %02X+%04X\n",dev->bus, dev->addr, reg, *value); + *value = d[1] | (d[0] << 8); + return error; } int ina3221_trigger(ina3221_t *dev) { - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); } int ina3221_getStatus(ina3221_t *dev) { - return _wireReadRegister(dev->addr, INA3221_REG_MASK, &dev->mask.mask_register); + return _wireReadRegister(&dev->i2c_dev, INA3221_REG_MASK, &dev->mask.mask_register); } int ina3221_sync(ina3221_t *dev) @@ -80,17 +51,17 @@ int ina3221_sync(ina3221_t *dev) uint16_t ptr_data; int err = 0; //////////////////////// Sync config register - if ((err = _wireReadRegister(dev->addr, INA3221_REG_CONFIG, &ptr_data))) // Read config + if ((err = _wireReadRegister(&dev->i2c_dev, INA3221_REG_CONFIG, &ptr_data))) // Read config return err; if( ptr_data != dev->config.config_register) { - if ((err = _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register))) // Update config + if ((err = _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register))) // Update config return err; } //////////////////////// Sync mask register config - if ((err = _wireReadRegister(dev->addr, INA3221_REG_MASK, &ptr_data))) // Read mask + if ((err = _wireReadRegister(&dev->i2c_dev, INA3221_REG_MASK, &ptr_data))) // Read mask return err; if( (ptr_data & INA3221_MASK_CONFIG) != (dev->mask.mask_register & INA3221_MASK_CONFIG)) { - if ((err = _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG))) // Update config + if ((err = _wireWriteRegister(&dev->i2c_dev, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG))) // Update config return err; } return 0; @@ -101,7 +72,7 @@ int ina3221_setting(ina3221_t *dev ,bool mode, bool bus, bool shunt) dev->config.mode = mode; dev->config.ebus = bus; dev->config.esht = shunt; - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); } int ina3221_enableChannel(ina3221_t *dev ,bool ch1, bool ch2, bool ch3) @@ -109,7 +80,7 @@ int ina3221_enableChannel(ina3221_t *dev ,bool ch1, bool ch2, bool ch3) dev->config.ch1 = ch1; dev->config.ch2 = ch2; dev->config.ch3 = ch3; - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); } int ina3221_enableChannelSum(ina3221_t *dev ,bool ch1, bool ch2, bool ch3) @@ -117,32 +88,32 @@ int ina3221_enableChannelSum(ina3221_t *dev ,bool ch1, bool ch2, bool ch3) dev->mask.scc1 = ch1; dev->mask.scc2 = ch2; dev->mask.scc3 = ch3; - return _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG); } int ina3221_enableLatchPin(ina3221_t *dev ,bool warning, bool critical) { dev->mask.wen = warning; dev->mask.cen = critical; - return _wireWriteRegister(dev->addr, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_MASK, dev->mask.mask_register & INA3221_MASK_CONFIG); } int ina3221_setAverage(ina3221_t *dev, ina3221_avg_t avg) { dev->config.avg = avg; - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); } int ina3221_setBusConversionTime(ina3221_t *dev,ina3221_ct_t ct) { dev->config.vbus = ct; - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); } int ina3221_setShuntConversionTime(ina3221_t *dev,ina3221_ct_t ct) { dev->config.vsht = ct; - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); } int ina3221_reset(ina3221_t *dev) @@ -150,14 +121,14 @@ int ina3221_reset(ina3221_t *dev) dev->config.config_register = INA3221_DEFAULT_CONFIG ; //dev reset dev->mask.mask_register = INA3221_DEFAULT_CONFIG ; //dev reset dev->config.rst = 1 ; - return _wireWriteRegister(dev->addr, INA3221_REG_CONFIG, dev->config.config_register); // send reset to device + return _wireWriteRegister(&dev->i2c_dev, INA3221_REG_CONFIG, dev->config.config_register); // send reset to device } int ina3221_getBusVoltage(ina3221_t *dev, ina3221_channel_t channel, float *voltage) { int16_t raw_value; int err = 0; - if ((err = _wireReadRegister(dev->addr,INA3221_REG_BUSVOLTAGE_1+channel*2, (uint16_t*)&raw_value))) + if ((err = _wireReadRegister(&dev->i2c_dev,INA3221_REG_BUSVOLTAGE_1+channel*2, (uint16_t*)&raw_value))) return err; *voltage = raw_value*0.001 ; //V 8mV step return 0; @@ -167,12 +138,12 @@ int ina3221_getShuntValue(ina3221_t *dev, ina3221_channel_t channel, float *volt { int16_t raw_value; int err = 0; - if ((err = _wireReadRegister(dev->addr,INA3221_REG_SHUNTVOLTAGE_1+channel*2, (uint16_t*)&raw_value))) + if ((err = _wireReadRegister(&dev->i2c_dev,INA3221_REG_SHUNTVOLTAGE_1+channel*2, (uint16_t*)&raw_value))) return err; *voltage = raw_value*0.005; //mV 40uV step if(!dev->shunt[channel]) { - debug("No shunt configured for channel %u. Dev:%X\n",channel+1, dev->addr); + debug("No shunt configured for channel %u. Dev:%u:%X\n",channel+1, dev->bus, dev->addr); return -EINVAL; } *current = (*voltage*1000.0)/dev->shunt[channel] ; //mA @@ -183,7 +154,7 @@ int ina3221_getSumShuntValue(ina3221_t *dev, float *voltage) { int16_t raw_value; int err = 0; - if ((err = _wireReadRegister(dev->addr,INA3221_REG_SHUNT_VOLTAGE_SUM, (uint16_t*)&raw_value))) + if ((err = _wireReadRegister(&dev->i2c_dev,INA3221_REG_SHUNT_VOLTAGE_SUM, (uint16_t*)&raw_value))) return err; *voltage = raw_value*0.02; //uV 40uV step return 0; @@ -192,39 +163,39 @@ int ina3221_getSumShuntValue(ina3221_t *dev, float *voltage) int ina3221_setCriticalAlert(ina3221_t *dev, ina3221_channel_t channel, float current) { int16_t raw_value = current*dev->shunt[channel]*0.2; // format - return _wireWriteRegister(dev->addr,INA3221_REG_CRITICAL_ALERT_1+channel*2, *(uint16_t*)&raw_value); + return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_CRITICAL_ALERT_1+channel*2, *(uint16_t*)&raw_value); } int ina3221_setWarningAlert(ina3221_t *dev, ina3221_channel_t channel, float current) { int16_t raw_value = current*dev->shunt[channel]*0.2 ; // format - return _wireWriteRegister(dev->addr,INA3221_REG_WARNING_ALERT_1+channel*2, *(uint16_t*)&raw_value); + return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_WARNING_ALERT_1+channel*2, *(uint16_t*)&raw_value); } int ina3221_setSumWarningAlert(ina3221_t *dev, float voltage) { int16_t raw_value = voltage*50.0 ; // format - return _wireWriteRegister(dev->addr,INA3221_REG_SHUNT_VOLTAGE_SUM_LIMIT, *(uint16_t*)&raw_value); + return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_SHUNT_VOLTAGE_SUM_LIMIT, *(uint16_t*)&raw_value); } int ina3221_setPowerValidUpperLimit(ina3221_t *dev, float voltage) { if(!dev->config.ebus) { - debug("Bus not enable. Dev:%X\n", dev->addr); + debug("Bus not enable. Dev:%u:%X\n", dev->bus, dev->addr); return -ENOTSUP; } int16_t raw_value = voltage*1000.0; //format - return _wireWriteRegister(dev->addr,INA3221_REG_VALID_POWER_UPPER_LIMIT, *(uint16_t*)&raw_value); + return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_VALID_POWER_UPPER_LIMIT, *(uint16_t*)&raw_value); } int ina3221_setPowerValidLowerLimit(ina3221_t *dev, float voltage) { if(!dev->config.ebus) { - debug("Bus not enable. Dev:%X\n", dev->addr); + debug("Bus not enable. Dev:%u:%X\n", dev->bus, dev->addr); return -ENOTSUP; } int16_t raw_value = voltage*1000.0; // round and format - return _wireWriteRegister(dev->addr,INA3221_REG_VALID_POWER_LOWER_LIMIT, *(uint16_t*)&raw_value); + return _wireWriteRegister(&dev->i2c_dev,INA3221_REG_VALID_POWER_LOWER_LIMIT, *(uint16_t*)&raw_value); } diff --git a/extras/ina3221/ina3221.h b/extras/ina3221/ina3221.h index 000919c..627f3aa 100644 --- a/extras/ina3221/ina3221.h +++ b/extras/ina3221/ina3221.h @@ -12,6 +12,8 @@ #include #include +#include +#include #ifdef __cplusplus extern "C" { @@ -130,7 +132,7 @@ typedef union * Device description */ typedef struct { - const uint8_t addr; // ina3221 I2C address + const i2c_dev_t i2c_dev; // ina3221 I2C address const uint16_t shunt[BUS_NUMBER]; //Memory of shunt value (mOhm) ina3221_config_t config; //Memory of ina3221 config ina3221_mask_t mask; //Memory of mask_config diff --git a/extras/mbedtls/include/mbedtls/config.h b/extras/mbedtls/include/mbedtls/config.h index 54ce5be..ed01596 100644 --- a/extras/mbedtls/include/mbedtls/config.h +++ b/extras/mbedtls/include/mbedtls/config.h @@ -3,6 +3,10 @@ * * \brief Configuration options (set of defines) * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + * * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved * SPDX-License-Identifier: Apache-2.0 * @@ -21,11 +25,6 @@ * This file is part of mbed TLS (https://tls.mbed.org) */ -/* - * This set of compile-time options may be used to enable - * or disable features selectively, and reduce the global - * memory footprint. - */ #ifndef MBEDTLS_CONFIG_H #define MBEDTLS_CONFIG_H @@ -72,6 +71,10 @@ * The time does not need to be correct, only time differences are used, * by contrast with MBEDTLS_HAVE_TIME_DATE * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * * Comment if your system does not support time functions */ //#define MBEDTLS_HAVE_TIME @@ -132,10 +135,10 @@ //#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS /** - * \def MBEDTLS_PLATFORM_XXX_ALT + * \def MBEDTLS_PLATFORM_EXIT_ALT * - * Uncomment a macro to let mbed TLS support the function in the platform - * abstraction layer. + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. * * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will * provide a function "mbedtls_platform_set_printf()" that allows you to set an @@ -149,13 +152,17 @@ * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as * MBEDTLS_PLATFORM_XXX_MACRO! * + * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME + * * Uncomment a macro to enable alternate implementation of specific base * platform function */ //#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_TIME_ALT //#define MBEDTLS_PLATFORM_FPRINTF_ALT //#define MBEDTLS_PLATFORM_PRINTF_ALT //#define MBEDTLS_PLATFORM_SNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT /** * \def MBEDTLS_DEPRECATED_WARNING @@ -208,19 +215,19 @@ //#define MBEDTLS_TIMING_ALT /** - * \def MBEDTLS__MODULE_NAME__ALT + * \def MBEDTLS_AES_ALT * - * Uncomment a macro to let mbed TLS use your alternate core implementation of - * a symmetric crypto or hash module (e.g. platform specific assembly - * optimized implementations). Keep in mind that the function prototypes - * should remain the same. + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto, an arithmetic or hash + * module (e.g. platform specific assembly optimized implementations). Keep + * in mind that the function prototypes should remain the same. * * This replaces the whole module. If you only want to replace one of the * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. * * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer - * provide the "struct mbedtls_aes_context" definition and omit the base function - * declarations and implementations. "aes_alt.h" will be included from + * provide the "struct mbedtls_aes_context" definition and omit the base + * function declarations and implementations. "aes_alt.h" will be included from * "aes.h" to include the new function definitions. * * Uncomment a macro to enable alternate implementation of the corresponding @@ -239,13 +246,23 @@ //#define MBEDTLS_SHA1_ALT //#define MBEDTLS_SHA256_ALT //#define MBEDTLS_SHA512_ALT +/* + * When replacing the elliptic curve module, pleace consider, that it is + * implemented with two .c files: + * - ecp.c + * - ecp_curves.c + * You can replace them very much like all the other MBEDTLS__MODULE_NAME__ALT + * macros as described above. The only difference is that you have to make sure + * that you provide functionality for both .c files. + */ +//#define MBEDTLS_ECP_ALT /** - * \def MBEDTLS__FUNCTION_NAME__ALT + * \def MBEDTLS_MD2_PROCESS_ALT * - * Uncomment a macro to let mbed TLS use you alternate core implementation of - * symmetric crypto or hash function. Keep in mind that function prototypes - * should remain the same. + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. * * This replaces only one function. The header file from mbed TLS is still * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. @@ -278,6 +295,76 @@ //#define MBEDTLS_AES_ENCRYPT_ALT //#define MBEDTLS_AES_DECRYPT_ALT +/** + * \def MBEDTLS_ECP_INTERNAL_ALT + * + * Expose a part of the internal interface of the Elliptic Curve Point module. + * + * MBEDTLS_ECP__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternative core implementation of elliptic curve arithmetic. Keep in mind + * that function prototypes should remain the same. + * + * This partially replaces one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS_ECP_ALT flag. The original implementation + * is still present and it is used for group structures not supported by the + * alternative. + * + * Any of these options become available by defining MBEDTLS_ECP_INTERNAL_ALT + * and implementing the following functions: + * unsigned char mbedtls_internal_ecp_grp_capable( + * const mbedtls_ecp_group *grp ) + * int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp ) + * void mbedtls_internal_ecp_deinit( const mbedtls_ecp_group *grp ) + * The mbedtls_internal_ecp_grp_capable function should return 1 if the + * replacement functions implement arithmetic for the given group and 0 + * otherwise. + * The functions mbedtls_internal_ecp_init and mbedtls_internal_ecp_deinit are + * called before and after each point operation and provide an opportunity to + * implement optimized set up and tear down instructions. + * + * Example: In case you uncomment MBEDTLS_ECP_INTERNAL_ALT and + * MBEDTLS_ECP_DOUBLE_JAC_ALT, mbed TLS will still provide the ecp_double_jac + * function, but will use your mbedtls_internal_ecp_double_jac if the group is + * supported (your mbedtls_internal_ecp_grp_capable function returns 1 when + * receives it as an argument). If the group is not supported then the original + * implementation is used. The other functions and the definition of + * mbedtls_ecp_group and mbedtls_ecp_point will not change, so your + * implementation of mbedtls_internal_ecp_double_jac and + * mbedtls_internal_ecp_grp_capable must be compatible with this definition. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +/* Required for all the functions in this section */ +//#define MBEDTLS_ECP_INTERNAL_ALT +/* Support for Weierstrass curves with Jacobi representation */ +//#define MBEDTLS_ECP_RANDOMIZE_JAC_ALT +//#define MBEDTLS_ECP_ADD_MIXED_ALT +//#define MBEDTLS_ECP_DOUBLE_JAC_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT +//#define MBEDTLS_ECP_NORMALIZE_JAC_ALT +/* Support for curves with Montgomery arithmetic */ +//#define MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT +//#define MBEDTLS_ECP_RANDOMIZE_MXZ_ALT +//#define MBEDTLS_ECP_NORMALIZE_MXZ_ALT + +/** + * \def MBEDTLS_TEST_NULL_ENTROPY + * + * Enables testing and use of mbed TLS without any configured entropy sources. + * This permits use of the library on platforms before an entropy source has + * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the + * MBEDTLS_ENTROPY_NV_SEED switches). + * + * WARNING! This switch MUST be disabled in production builds, and is suitable + * only for development. + * Enabling the switch negates any security provided by the library. + * + * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + */ +//#define MBEDTLS_TEST_NULL_ENTROPY + /** * \def MBEDTLS_ENTROPY_HARDWARE_ALT * @@ -365,10 +452,11 @@ //#define MBEDTLS_CIPHER_NULL_CIPHER /** - * \def MBEDTLS_CIPHER_PADDING_XXX + * \def MBEDTLS_CIPHER_PADDING_PKCS7 * - * Uncomment or comment macros to add support for specific padding modes - * in the cipher layer with cipher modes that support padding (e.g. CBC) + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) * * If you disable all padding modes, only full blocks can be used with CBC. * @@ -408,10 +496,10 @@ #define MBEDTLS_REMOVE_ARC4_CIPHERSUITES /** - * \def MBEDTLS_ECP_XXXX_ENABLED + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED * - * Enables specific curves within the Elliptic Curve module. - * By default all supported curves are enabled. + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. * * Comment macros to disable the curve and functions for it */ @@ -695,6 +783,25 @@ */ #define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + /** * \def MBEDTLS_PK_PARSE_EC_EXTENDED * @@ -780,6 +887,34 @@ */ #define MBEDTLS_ENTROPY_FORCE_SHA256 +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +//#define MBEDTLS_ENTROPY_NV_SEED + /** * \def MBEDTLS_MEMORY_DEBUG * @@ -869,18 +1004,6 @@ */ #define MBEDTLS_SHA256_SMALLER -/** - * \def MBEDTLS_SSL_AEAD_RANDOM_IV - * - * Generate a random IV rather than using the record sequence number as a - * nonce for ciphersuites using and AEAD algorithm (GCM or CCM). - * - * Using the sequence number is generally recommended. - * - * Uncomment this macro to always use random IVs with AEAD ciphersuites. - */ -//#define MBEDTLS_SSL_AEAD_RANDOM_IV - /** * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES * @@ -1040,7 +1163,7 @@ * * Comment this macro to disable support for SSL 3.0 */ -#define MBEDTLS_SSL_PROTO_SSL3 +//#define MBEDTLS_SSL_PROTO_SSL3 /** * \def MBEDTLS_SSL_PROTO_TLS1 @@ -1135,6 +1258,22 @@ */ #define MBEDTLS_SSL_DTLS_HELLO_VERIFY +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + /** * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT * @@ -1160,6 +1299,16 @@ */ #define MBEDTLS_SSL_SESSION_TICKETS +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +#define MBEDTLS_SSL_EXPORT_KEYS + /** * \def MBEDTLS_SSL_SERVER_NAME_INDICATION * @@ -1231,6 +1380,8 @@ * If set, the X509 parser will not break-off when parsing an X509 certificate * and encountering an unknown critical extension. * + * \warning Depending on your PKI use, enabling this can be a security risk! + * * Uncomment to prevent an error. */ //#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION @@ -1438,7 +1589,7 @@ * library/pkwrite.c * library/x509_create.c * library/x509write_crt.c - * library/mbedtls_x509write_csr.c + * library/x509write_csr.c */ #define MBEDTLS_ASN1_WRITE_C @@ -1572,6 +1723,19 @@ */ #define MBEDTLS_CIPHER_C +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +//#define MBEDTLS_CMAC_C + /** * \def MBEDTLS_CTR_DRBG_C * @@ -1671,6 +1835,25 @@ */ #define MBEDTLS_ECDSA_C +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + /** * \def MBEDTLS_ECP_C * @@ -1679,6 +1862,7 @@ * Module: library/ecp.c * Caller: library/ecdh.c * library/ecdsa.c + * library/ecjpake.c * * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED */ @@ -1766,7 +1950,7 @@ * * Enable the generic message digest layer. * - * Module: library/mbedtls_md.c + * Module: library/md.c * Caller: * * Uncomment to enable generic message digest wrappers. @@ -1778,7 +1962,7 @@ * * Enable the MD2 hash algorithm. * - * Module: library/mbedtls_md2.c + * Module: library/md2.c * Caller: * * Uncomment to enable support for (rare) MD2-signed X.509 certs. @@ -1790,7 +1974,7 @@ * * Enable the MD4 hash algorithm. * - * Module: library/mbedtls_md4.c + * Module: library/md4.c * Caller: * * Uncomment to enable support for (rare) MD4-signed X.509 certs. @@ -1802,8 +1986,8 @@ * * Enable the MD5 hash algorithm. * - * Module: library/mbedtls_md5.c - * Caller: library/mbedtls_md.c + * Module: library/md5.c + * Caller: library/md.c * library/pem.c * library/ssl_tls.c * @@ -1831,11 +2015,19 @@ /** * \def MBEDTLS_NET_C * - * Enable the TCP/IP networking routines. + * Enable the TCP and UDP over IPv6/IPv4 networking routines. * - * Module: library/net.c + * \note This module only works on POSIX/Unix (including Linux, BSD and OS X) + * and Windows. For other platforms, you'll want to disable it, and write your + * own networking callbacks to be passed to \c mbedtls_ssl_set_bio(). * - * This module provides TCP/IP networking routines. + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/net_sockets.c + * + * This module provides networking routines. */ #define MBEDTLS_NET_C @@ -1852,11 +2044,11 @@ * library/rsa.c * library/x509.c * library/x509_create.c - * library/mbedtls_x509_crl.c - * library/mbedtls_x509_crt.c - * library/mbedtls_x509_csr.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c * library/x509write_crt.c - * library/mbedtls_x509write_csr.c + * library/x509write_csr.c * * This modules translates between OIDs and internal values. */ @@ -1884,9 +2076,9 @@ * Module: library/pem.c * Caller: library/dhm.c * library/pkparse.c - * library/mbedtls_x509_crl.c - * library/mbedtls_x509_crt.c - * library/mbedtls_x509_csr.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c * * Requires: MBEDTLS_BASE64_C * @@ -1902,7 +2094,7 @@ * Module: library/pem.c * Caller: library/pkwrite.c * library/x509write_crt.c - * library/mbedtls_x509write_csr.c + * library/x509write_csr.c * * Requires: MBEDTLS_BASE64_C * @@ -1932,8 +2124,8 @@ * Enable the generic public (asymetric) key parser. * * Module: library/pkparse.c - * Caller: library/mbedtls_x509_crt.c - * library/mbedtls_x509_csr.c + * Caller: library/x509_crt.c + * library/x509_csr.c * * Requires: MBEDTLS_PK_C * @@ -2024,8 +2216,8 @@ * * Enable the RIPEMD-160 hash algorithm. * - * Module: library/mbedtls_ripemd160.c - * Caller: library/mbedtls_md.c + * Module: library/ripemd160.c + * Caller: library/md.c * */ #define MBEDTLS_RIPEMD160_C @@ -2053,14 +2245,15 @@ * * Enable the SHA1 cryptographic hash algorithm. * - * Module: library/mbedtls_sha1.c - * Caller: library/mbedtls_md.c + * Module: library/sha1.c + * Caller: library/md.c * library/ssl_cli.c * library/ssl_srv.c * library/ssl_tls.c * library/x509write_crt.c * - * This module is required for SSL/TLS and SHA1-signed certificates. + * This module is required for SSL/TLS up to version 1.1, for TLS 1.2 + * depending on the handshake parameters, and for SHA1-signed certificates. */ #define MBEDTLS_SHA1_C @@ -2069,9 +2262,9 @@ * * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. * - * Module: library/mbedtls_sha256.c + * Module: library/sha256.c * Caller: library/entropy.c - * library/mbedtls_md.c + * library/md.c * library/ssl_cli.c * library/ssl_srv.c * library/ssl_tls.c @@ -2086,9 +2279,9 @@ * * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. * - * Module: library/mbedtls_sha512.c + * Module: library/sha512.c * Caller: library/entropy.c - * library/mbedtls_md.c + * library/md.c * library/ssl_cli.c * library/ssl_srv.c * @@ -2181,7 +2374,8 @@ * By default mbed TLS assumes it is used in a non-threaded environment or that * contexts are not shared between threads. If you do intend to use contexts * between threads, you will need to enable this layer to prevent race - * conditions. + * conditions. See also our Knowledge Base article about threading: + * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading * * Module: library/threading.c * @@ -2198,7 +2392,18 @@ /** * \def MBEDTLS_TIMING_C * - * Enable the portable timing interface. + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS * * Module: library/timing.c * Caller: library/havege.c @@ -2224,9 +2429,9 @@ * Enable X.509 core for using certificates. * * Module: library/x509.c - * Caller: library/mbedtls_x509_crl.c - * library/mbedtls_x509_crt.c - * library/mbedtls_x509_csr.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c * * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, * MBEDTLS_PK_PARSE_C @@ -2240,7 +2445,7 @@ * * Enable X.509 certificate parsing. * - * Module: library/mbedtls_x509_crt.c + * Module: library/x509_crt.c * Caller: library/ssl_cli.c * library/ssl_srv.c * library/ssl_tls.c @@ -2256,8 +2461,8 @@ * * Enable X.509 CRL parsing. * - * Module: library/mbedtls_x509_crl.c - * Caller: library/mbedtls_x509_crt.c + * Module: library/x509_crl.c + * Caller: library/x509_crt.c * * Requires: MBEDTLS_X509_USE_C * @@ -2270,7 +2475,7 @@ * * Enable X.509 Certificate Signing Request (CSR) parsing. * - * Module: library/mbedtls_x509_csr.c + * Module: library/x509_csr.c * Caller: library/x509_crt_write.c * * Requires: MBEDTLS_X509_USE_C @@ -2347,12 +2552,12 @@ /* MPI / BIGNUM options */ #define MBEDTLS_MPI_WINDOW_SIZE 1 /**< Maximum windows size used. */ -#define MBEDTLS_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ +#define MBEDTLS_MPI_MAX_SIZE 512 /**< Maximum number of bytes for usable MPIs. */ /* CTR_DRBG options */ //#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ /* this is normally 10x higher, but reseeding seems quite inexpensive on esp8266 */ -#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 1000 /**< Interval before reseed is performed by default */ +#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 1000 /**< Interval before reseed is performed by default */ //#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ //#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ //#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ @@ -2371,6 +2576,7 @@ /* Entropy options */ //#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ //#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ /* Memory buffer allocator options */ //#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ @@ -2380,27 +2586,37 @@ //#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ //#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ //#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ /* Note: your snprintf must correclty zero-terminate the buffer! */ //#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ /* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ /* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ //#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ //#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ //#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ //#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ //#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ /* Note: your snprintf must correclty zero-terminate the buffer! */ //#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ /* SSL Cache options */ //#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ //#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ /* SSL options */ -#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ //#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ //#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ //#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ @@ -2421,11 +2637,35 @@ /* X509 options */ //#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ -/* \} name SECTION: Module configuration options */ +/** + * Allow SHA-1 in the default TLS configuration for certificate signing. + * Without this build-time option, SHA-1 support must be activated explicitly + * through mbedtls_ssl_conf_cert_profile. Turning on this option is not + * recommended because of it is possible to generte SHA-1 collisions, however + * this may be safe for legacy infrastructure where additional controls apply. + */ +// #define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES -#if defined(TARGET_LIKE_MBED) -#include "mbedtls/target_config.h" +/** + * Allow SHA-1 in the default TLS configuration for TLS 1.2 handshake + * signature and ciphersuite selection. Without this build-time option, SHA-1 + * support must be activated explicitly through mbedtls_ssl_conf_sig_hashes. + * The use of SHA-1 in TLS <= 1.1 and in HMAC-SHA-1 is always allowed by + * default. At the time of writing, there is no practical attack on the use + * of SHA-1 in handshake signatures, hence this option is turned on by default + * for compatibility with existing peers. + */ +#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations */ +//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h" + +#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE #endif /* diff --git a/extras/mbedtls/mbedtls b/extras/mbedtls/mbedtls index 0a0c22e..f2a597f 160000 --- a/extras/mbedtls/mbedtls +++ b/extras/mbedtls/mbedtls @@ -1 +1 @@ -Subproject commit 0a0c22e0efcf2f8f71d7e16712f80b8f77326f72 +Subproject commit f2a597fa3dd1c7b15e0fee62f6932b253295803d diff --git a/extras/mbedtls/net_lwip.c b/extras/mbedtls/net_lwip.c index e6f7183..67453c8 100644 --- a/extras/mbedtls/net_lwip.c +++ b/extras/mbedtls/net_lwip.c @@ -29,7 +29,7 @@ #if defined(MBEDTLS_NET_C) -#include "mbedtls/net.h" +#include "mbedtls/net_sockets.h" #include diff --git a/extras/mcp4725/mcp4725.c b/extras/mcp4725/mcp4725.c index 889ddef..a478e67 100644 --- a/extras/mcp4725/mcp4725.c +++ b/extras/mcp4725/mcp4725.c @@ -6,66 +6,59 @@ * BSD Licensed as described in the file LICENSE */ #include "mcp4725.h" -#include #define CMD_DAC 0x40 #define CMD_EEPROM 0x60 #define BIT_READY 0x80 -static void read_data(uint8_t addr, uint8_t *buf, uint8_t size) +static void read_data(i2c_dev_t* dev, uint8_t *buf, uint8_t size) { - i2c_start(); - i2c_write(addr << 1 | 1); - while (size--) - *(buf++) = i2c_read(!size); - i2c_stop(); + i2c_slave_read(dev->bus, dev->addr , NULL, buf, size); } -bool mcp4725_eeprom_busy(uint8_t addr) +bool mcp4725_eeprom_busy(i2c_dev_t* dev) { uint8_t res; - read_data(addr, &res, 1); + read_data(dev, &res, 1); return !(res & BIT_READY); } -mcp4725_power_mode_t mcp4725_get_power_mode(uint8_t addr, bool eeprom) +mcp4725_power_mode_t mcp4725_get_power_mode(i2c_dev_t* dev, bool eeprom) { uint8_t buf[4]; - read_data(addr, buf, eeprom ? 4 : 1); + read_data(dev, buf, eeprom ? 4 : 1); return (eeprom ? buf[3] >> 5 : buf[0] >> 1) & 0x03; } -void mcp4725_set_power_mode(uint8_t addr, mcp4725_power_mode_t mode, bool eeprom) +void mcp4725_set_power_mode(i2c_dev_t* dev, mcp4725_power_mode_t mode, bool eeprom) { - uint16_t value = mcp4725_get_raw_output(addr, eeprom); + uint16_t value = mcp4725_get_raw_output(dev, eeprom); uint8_t data[] = { (eeprom ? CMD_EEPROM : CMD_DAC) | ((uint8_t)mode << 1), value >> 4, value << 4 }; - i2c_slave_write(addr, data, 3); + i2c_slave_write(dev->bus, dev->addr, &data[0], &data[1], 2); } -uint16_t mcp4725_get_raw_output(uint8_t addr, bool eeprom) +uint16_t mcp4725_get_raw_output(i2c_dev_t* dev, bool eeprom) { uint8_t buf[5]; - read_data(addr, buf, eeprom ? 5 : 3); + read_data(dev, buf, eeprom ? 5 : 3); return eeprom ? ((uint16_t)(buf[3] & 0x0f) << 8) | buf[4] : ((uint16_t)buf[0] << 4) | (buf[1] >> 4); } -void mcp4725_set_raw_output(uint8_t addr, uint16_t value, bool eeprom) +void mcp4725_set_raw_output(i2c_dev_t* dev, uint16_t value, bool eeprom) { uint8_t data[] = { (eeprom ? CMD_EEPROM : CMD_DAC), value >> 4, value << 4 }; - i2c_slave_write(addr, data, 3); + i2c_slave_write(dev->bus, dev->addr, &data[0], &data[1], 2); } - - diff --git a/extras/mcp4725/mcp4725.h b/extras/mcp4725/mcp4725.h index ac6d905..edb29de 100644 --- a/extras/mcp4725/mcp4725.h +++ b/extras/mcp4725/mcp4725.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -41,7 +42,7 @@ typedef enum * @param addr Device address * @return true when EEPROM is busy */ -bool mcp4725_eeprom_busy(uint8_t addr); +bool mcp4725_eeprom_busy(i2c_dev_t* dev); /** * Get power mode @@ -49,7 +50,7 @@ bool mcp4725_eeprom_busy(uint8_t addr); * @param eeprom Read power mode from EEPROM if true * @return Power mode */ -mcp4725_power_mode_t mcp4725_get_power_mode(uint8_t addr, bool eeprom); +mcp4725_power_mode_t mcp4725_get_power_mode(i2c_dev_t* dev, bool eeprom); /** * Set power mode @@ -57,7 +58,7 @@ mcp4725_power_mode_t mcp4725_get_power_mode(uint8_t addr, bool eeprom); * @param mode Power mode * @param eeprom Store mode to device EEPROM if true */ -void mcp4725_set_power_mode(uint8_t addr, mcp4725_power_mode_t mode, bool eeprom); +void mcp4725_set_power_mode(i2c_dev_t* dev, mcp4725_power_mode_t mode, bool eeprom); /** * Get current DAC value @@ -65,7 +66,7 @@ void mcp4725_set_power_mode(uint8_t addr, mcp4725_power_mode_t mode, bool eeprom * @param eeprom Read value from device EEPROM if true * @return Raw output value, 0..4095 */ -uint16_t mcp4725_get_raw_output(uint8_t addr, bool eeprom); +uint16_t mcp4725_get_raw_output(i2c_dev_t* dev, bool eeprom); /** * Set DAC output value @@ -73,7 +74,7 @@ uint16_t mcp4725_get_raw_output(uint8_t addr, bool eeprom); * @param value Raw output value, 0..4095 * @param eeprom Store value to device EEPROM if true */ -void mcp4725_set_raw_output(uint8_t addr, uint16_t value, bool eeprom); +void mcp4725_set_raw_output(i2c_dev_t* dev, uint16_t value, bool eeprom); /** * Get current DAC output voltage @@ -82,9 +83,9 @@ void mcp4725_set_raw_output(uint8_t addr, uint16_t value, bool eeprom); * @param eeprom Read voltage from device EEPROM if true * @return Current output voltage, volts */ -inline float mcp4725_get_voltage(uint8_t addr, float vdd, bool eeprom) +inline float mcp4725_get_voltage(i2c_dev_t* dev, float vdd, bool eeprom) { - return vdd / MCP4725_MAX_VALUE * mcp4725_get_raw_output(addr, eeprom); + return vdd / MCP4725_MAX_VALUE * mcp4725_get_raw_output(dev, eeprom); } /** @@ -94,9 +95,9 @@ inline float mcp4725_get_voltage(uint8_t addr, float vdd, bool eeprom) * @param value Output value, volts * @param eeprom Store value to device EEPROM if true */ -inline void mcp4725_set_voltage(uint8_t addr, float vdd, float value, bool eeprom) +inline void mcp4725_set_voltage(i2c_dev_t* dev, float vdd, float value, bool eeprom) { - mcp4725_set_raw_output(addr, MCP4725_MAX_VALUE / vdd * value, eeprom); + mcp4725_set_raw_output(dev, MCP4725_MAX_VALUE / vdd * value, eeprom); } #ifdef __cplusplus diff --git a/extras/mdnsresponder/component.mk b/extras/mdnsresponder/component.mk new file mode 100644 index 0000000..68c16f1 --- /dev/null +++ b/extras/mdnsresponder/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/mdnsresponder + +INC_DIRS += $(mdnsresponder_ROOT) + +# args for passing into compile rule generation +mdnsresponder_INC_DIR = $(mdnsresponder_ROOT) +mdnsresponder_SRC_DIR = $(mdnsresponder_ROOT) + +$(eval $(call component_compile_rules,mdnsresponder)) diff --git a/extras/mdnsresponder/mdnsresponder.c b/extras/mdnsresponder/mdnsresponder.c new file mode 100644 index 0000000..30ff75e --- /dev/null +++ b/extras/mdnsresponder/mdnsresponder.c @@ -0,0 +1,797 @@ +/* + * Basic multicast DNS responder + * + * Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN, + * so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc + * See RFC6762, RFC6763 + * + * This sample code is in the public domain. + * + * by M J A Hamel 2016 + */ + + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mdnsresponder.h" + +#define qDebugLog // Log activity generally +#define qLogIncoming // Log all arriving multicast packets +#define qLogAllTraffic // Log and decode all mDNS packets + +#define kMDNSStackSize 800 + +#define DNS_MULTICAST_ADDRESS "224.0.0.251" // RFC 6762 +#define DNS_MDNS_PORT 5353 // RFC 6762 + +//------------------------------------------------------------------- + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif + +PACK_STRUCT_BEGIN +/** DNS message header */ +struct mdns_hdr { + PACK_STRUCT_FIELD(u16_t id); + PACK_STRUCT_FIELD(u8_t flags1); + PACK_STRUCT_FIELD(u8_t flags2); + PACK_STRUCT_FIELD(u16_t numquestions); + PACK_STRUCT_FIELD(u16_t numanswers); + PACK_STRUCT_FIELD(u16_t numauthrr); + PACK_STRUCT_FIELD(u16_t numextrarr); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define SIZEOF_DNS_HDR 12 + +PACK_STRUCT_BEGIN +/** MDNS query message structure */ +struct mdns_query { + /* MDNS query record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END + +#define SIZEOF_DNS_QUERY 4 + +PACK_STRUCT_BEGIN +/** MDNS answer message structure */ +struct mdns_answer { + /* MDNS answer record starts with either a domain name or a pointer + to a name already present somewhere in the packet. */ + PACK_STRUCT_FIELD(u16_t type); + PACK_STRUCT_FIELD(u16_t class); + PACK_STRUCT_FIELD(u32_t ttl); + PACK_STRUCT_FIELD(u16_t len); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#define SIZEOF_DNS_ANSWER 10 + +PACK_STRUCT_BEGIN +struct mdns_rr_srv { + /* RR SRV */ + PACK_STRUCT_FIELD(u16_t prio); + PACK_STRUCT_FIELD(u16_t weight); + PACK_STRUCT_FIELD(u16_t port); +}PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#define SIZEOF_DNS_RR_SRV 6 + + +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define vTaskDelayMs(ms) vTaskDelay((ms)/portTICK_PERIOD_MS) +#define UNUSED_ARG(x) (void)x +#define kDummyDataSize 8 // arbitrary, dynamically resized +#define kMaxNameSize 64 +#define kMaxQStr 128 // max incoming question key handled + +typedef struct mdns_rsrc { + struct mdns_rsrc* rNext; + u16_t rType; + u32_t rTTL; + u16_t rKeySize; + u16_t rDataSize; + char rData[kDummyDataSize]; // Key, as C str with . seperators, followed by data in network-ready form + // at rData[rKeySize] +} mdns_rsrc; + +static struct udp_pcb* gMDNS_pcb = NULL; +static ip_addr_t gMulticastAddr; // == DNS_MULTICAST_ADDRESS +static mdns_rsrc* gDictP = NULL; // RR database, linked list + +//---------------------- Debug/logging utilities ------------------------- + +#ifdef qDebugLog + + // DNS field TYPE used for "Resource Records", some additions + #define DNS_RRTYPE_AAAA 28 /* IPv6 host address */ + #define DNS_RRTYPE_SRV 33 /* Service record */ + #define DNS_RRTYPE_OPT 41 /* EDNS0 OPT record */ + #define DNS_RRTYPE_NSEC 47 /* NSEC record */ + #define DNS_RRTYPE_TSIG 250 /* Transaction Signature */ + #define DNS_RRTYPE_ANY 255 /* Not a DNS type, but a DNS query type, meaning "all types"*/ + + // DNS field CLASS used for "Resource Records" + #define DNS_RRCLASS_ANY 255 /* Any class (q) */ + + #define DNS_FLAG1_RESP 0x80 + #define DNS_FLAG1_OPMASK 0x78 + #define DNS_FLAG1_AUTH 0x04 + #define DNS_FLAG1_TRUNC 0x02 + #define DNS_FLAG1_RD 0x01 + #define DNS_FLAG2_RA 0x80 + #define DNS_FLAG2_RESMASK 0x0F + + static char qstr[12]; + + static char* mdns_qrtype(uint16_t typ) + { + switch(typ) { + case DNS_RRTYPE_A : return ("A"); + case DNS_RRTYPE_NS : return ("NS"); + case DNS_RRTYPE_PTR : return ("PTR"); + case DNS_RRTYPE_TXT : return ("TXT "); + case DNS_RRTYPE_AAAA : return ("AAAA"); + case DNS_RRTYPE_SRV : return ("SRV "); + case DNS_RRTYPE_NSEC : return ("NSEC "); + case DNS_RRTYPE_ANY : return ("ANY"); + } + sprintf(qstr,"type %d",typ); + return qstr; + } + + #ifdef qLogAllTraffic + + static void mdns_printhex(u8_t* p, int n) + { + int i; + for (i=0; i",n); + n = 0; + } else { + for (i=0; i0); + return (u8_t*)cp; + } + + + static u8_t* mdns_print_header(struct mdns_hdr* hdr) + { + if (hdr->flags1 & DNS_FLAG1_RESP) { + printf("Response, ID $%X %s ", htons(hdr->id), (hdr->flags1 & DNS_FLAG1_AUTH) ? "Auth " : "Non-auth "); + if (hdr->flags2 & DNS_FLAG2_RA) printf("RA "); + if ((hdr->flags2 & DNS_FLAG2_RESMASK)==0) printf("noerr"); + else printf("err %d", hdr->flags2 & DNS_FLAG2_RESMASK); + } else { + printf("Query, ID $%X op %d", htons(hdr->id), (hdr->flags1>>4) & 0x7 ); + } + if (hdr->flags1 & DNS_FLAG1_RD) printf("RD "); + if (hdr->flags1 & DNS_FLAG1_TRUNC) printf("[TRUNC] "); + + printf(": %d questions", htons(hdr->numquestions) ); + if (hdr->numanswers != 0) + printf(", %d answers",htons(hdr->numanswers)); + if (hdr->numauthrr != 0) + printf(", %d auth RR",htons(hdr->numauthrr)); + if (hdr->numextrarr != 0) + printf(", %d extra RR",htons(hdr->numextrarr)); + putchar('\n'); + return (u8_t*)hdr + SIZEOF_DNS_HDR; + } + + static u8_t* mdns_print_query(u8_t* p) + // Copy needed because it may be misaligned + { + struct mdns_query q; + uint16_t c; + + memcpy(&q,p,SIZEOF_DNS_QUERY); + c = htons(q.class); + printf(" %s %s", mdns_qrtype(htons(q.type)), mdns_qclass(c & 0x7FFF) ); + if (c & 0x8000) printf(" unicast-req"); + printf("\n"); + return p + SIZEOF_DNS_QUERY; + } + + static u8_t* mdns_print_answer(u8_t* p, struct mdns_hdr* hp) + // Copy needed because it may be misaligned + { + struct mdns_answer ans; + u16_t rrlen, atype, rrClass;; + + memcpy(&ans,p,SIZEOF_DNS_ANSWER); + atype = htons(ans.type); + rrlen = htons(ans.len); + rrClass = htons(ans.class); + printf(" %s %s TTL %d ", mdns_qrtype(atype), mdns_qclass(rrClass & 0x7FFF), htonl(ans.ttl)); + if (rrClass & 0x8000) + printf("cache-flush "); + if (rrlen > 0) { + u8_t* rp = p + SIZEOF_DNS_ANSWER; + if (atype==DNS_RRTYPE_A && rrlen==4) { + printf("%d.%d.%d.%d\n",rp[0],rp[1],rp[2],rp[3]); + } else if (atype==DNS_RRTYPE_PTR) { + mdns_print_name(rp, hp); + printf("\n"); + } else if (atype==DNS_RRTYPE_TXT) { + mdns_print_pstr(rp); + printf("\n"); + } else if (atype==DNS_RRTYPE_SRV && rrlen > SIZEOF_DNS_RR_SRV) { + struct mdns_rr_srv srvRR; + memcpy(&srvRR,rp,SIZEOF_DNS_RR_SRV); + printf("prio %d, weight %d, port %d, target ", srvRR.prio, srvRR.weight, srvRR.port); + mdns_print_name(rp + SIZEOF_DNS_RR_SRV, hp); + printf("\n"); + } else { + printf("%db:",rrlen); + mdns_printhex(rp,rrlen); + } + } else + printf("\n"); + return p + SIZEOF_DNS_ANSWER + rrlen; + } + + static int mdns_print_msg(u8_t* msgP, int msgLen) + { + int i; + u8_t* tp; + u8_t* limP = msgP + msgLen; + struct mdns_hdr* hdr; + + hdr = (struct mdns_hdr*) msgP; + tp = mdns_print_header(hdr); + for (i=0; inumquestions); i++) { + printf(" Q%d: ",i+1); + tp = mdns_print_name(tp,hdr); + tp = mdns_print_query(tp); + if (tp > limP) return 0; + } + + for (i=0; inumanswers); i++) { + printf(" A%d: ",i+1); + tp = mdns_print_name(tp,hdr); + tp = mdns_print_answer(tp,hdr); + if (tp > limP) return 0; + } + + for (i=0; inumauthrr); i++) { + printf(" AuRR%d: ",i+1); + tp = mdns_print_name(tp,hdr); + tp = mdns_print_answer(tp,hdr); + if (tp > limP) return 0; + } + + for (i=0; inumextrarr); i++) { + printf(" ExRR%d: ",i+1); + tp = mdns_print_name(tp,hdr); + tp = mdns_print_answer(tp,hdr); + if (tp > limP) return 0; + } + return 1; + } + #endif + +#endif // qDebugLog + +//--------------------------------------------------------------------------- + +static u8_t* mdns_labels2str(u8_t* hdrP, u8_t* p, char* qStr) +// Convert a DNS domain name label sequence into C string with . seperators +// Handles compression +{ + int i, n; + + do { + n = *p++; + if ((n & 0xC0) == 0xC0) { + n = (n & 0x3F) << 8; + n |= (u8_t)*p++; + mdns_labels2str( hdrP, hdrP + n, qStr); + return p; + } else if (n & 0xC0) { + printf(">>> mdns_labels2str,label $%X?",n); + return p; + } else { + for (i=0; i0); + return p; +} + +static int mdns_str2labels(const char* name, u8_t* lseq, int max) +// Encode a .. as a sequence of labels, return length +{ + int i,n,sdx,idx = 0; + int lc = 0; + + do { + sdx = idx; + while (name[idx] != '.' && name[idx] != 0) idx++; + n = idx-sdx; + *lseq++ = n; + lc++; + if (lc+n > max) { + printf(">>> mdns_str2labels: oversize (%d)\n",lc+n); + return 0; + } + for (i=0; i0); + return lc; +} + +static u8_t* mdns_get_question(u8_t* hdrP, u8_t* qp, char* qStr, uint16_t* qClass, uint16_t* qType, u8_t* qUnicast) +// Unpack a DNS question RR at qp, return pointer to next RR +{ + struct mdns_query qr; + uint16_t cls; + + qp = mdns_labels2str(hdrP, qp, qStr); + memcpy(&qr,qp,SIZEOF_DNS_QUERY); + *qType = htons(qr.type); + cls = htons(qr.class); + *qUnicast = cls>>15; + *qClass = cls & 0x7FFF; + return qp + SIZEOF_DNS_QUERY; +} + +//--------------------------------------------------------------------------- + + +static void mdns_add_response(const char* vKey, u16_t vType, u32_t ttl, const void* dataP, u16_t vDataSize) +// Add a record to the RR database list +{ + mdns_rsrc* rsrcP; + int keyLen, recSize; + + keyLen = strlen(vKey) + 1; + recSize = sizeof(mdns_rsrc) - kDummyDataSize + keyLen + vDataSize; + rsrcP = (mdns_rsrc*)malloc(recSize); + if (rsrcP==NULL) + printf(">>> mdns_add_response: couldn't alloc %d\n",recSize); + else { + rsrcP->rType = vType; + rsrcP->rTTL = ttl; + rsrcP->rKeySize = keyLen; + rsrcP->rDataSize = vDataSize; + memcpy(rsrcP->rData, vKey, keyLen); + memcpy(&rsrcP->rData[keyLen], dataP, vDataSize); + rsrcP->rNext = gDictP; + gDictP = rsrcP; + #ifdef qDebugLog + printf("mDNS added RR '%s' %s, %d bytes\n", vKey, mdns_qrtype(vType), vDataSize); + #endif + } +} + +void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nmStr) +{ + int nl; + u8_t lBuff[kMaxNameSize]; + + nl = mdns_str2labels(nmStr,lBuff,sizeof(lBuff)); + if (nl>0) + mdns_add_response(rKey, DNS_RRTYPE_PTR, ttl, lBuff, nl); +} + +void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targName) +{ + typedef struct SrvRec { + struct mdns_rr_srv srvRR; + u8_t lBuff[kMaxNameSize]; + } __attribute__((packed)) SrvRec; + + int nl; + SrvRec temp; + + temp.srvRR.prio = 0; + temp.srvRR.weight = 0; + temp.srvRR.port = htons(rPort); + nl = mdns_str2labels(targName,temp.lBuff,sizeof(temp.lBuff)); + if (nl>0) + mdns_add_response(rKey, DNS_RRTYPE_SRV, ttl, &temp, SIZEOF_DNS_RR_SRV + nl); +} + +void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txStr) +// Single TXT str, can be concatenated +{ + char pstr[256]; + u16_t n = strlen(txStr); + if (n > 255) + printf(">>> mdns_add_TXT oversize (%d)\n",n); + else { + pstr[0] = n; + memcpy(&pstr[1],txStr,n); + mdns_add_response(rKey, DNS_RRTYPE_TXT, ttl, txStr, n+1); + } +} + +void mdns_add_A(const char* rKey, u32_t ttl, struct ip_addr addr) +{ + mdns_add_response(rKey, DNS_RRTYPE_A, ttl, &addr, sizeof(addr)); +} + +void mdns_add_facility( const char* instanceName, // Friendly name, need not be unique + const char* serviceName, // Must be _name + const char* addText, // Must be = + mdns_flags flags, // TCP or UDP + u16_t onPort, // port number + u32_t ttl // seconds + ) +{ + char key[64]; + char fullName[128]; + char devName[96]; + struct ip_info ipInfo; + + #ifdef qDebugLog + printf("\nmDNS advertising instance %s protocol %s text %s on port %d %s TTL %d secs\n", + instanceName,serviceName,addText,onPort,(flags & mdns_UDP) ? "UDP" : "TCP", ttl); + #endif + + snprintf(key,sizeof(key),"%s.%s.local.",serviceName,(flags & mdns_UDP) ? "_udp" :"_tcp"); + snprintf(fullName,sizeof(fullName),"%s.%s",instanceName,key); + snprintf(devName,sizeof(devName),"%s.local.",instanceName); + + if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo)) + ipInfo.ip.addr = IPADDR_NONE; + + // Order has significance for extraRR feature + mdns_add_TXT(fullName,ttl,addText); + mdns_add_A(devName,ttl,ipInfo.ip); + mdns_add_SRV(fullName,ttl,onPort,devName); + mdns_add_PTR(key,ttl,fullName); + + // Optional, makes us browsable + if (flags & mdns_Browsable) + mdns_add_PTR("_services._dns-sd._udp.local.",ttl,key); + +} + +static void mdns_update_ipaddr(struct ip_info* ipInfo) +// IP address has been defined/changed: update any A records with the new IP +{ + mdns_rsrc* rp = gDictP; + while (rp != NULL) { + if (rp->rType==DNS_RRTYPE_A) { + #ifdef qDebugLog + printf("Updating A record for '%s' to %d.%d.%d.%d\n", rp->rData, + ip4_addr1(&ipInfo->ip), ip4_addr2(&ipInfo->ip), ip4_addr3(&ipInfo->ip), ip4_addr4(&ipInfo->ip)); + #endif + memcpy(&rp->rData[rp->rKeySize], &ipInfo->ip, sizeof(ip_addr_t)); + } + rp = rp->rNext; + } +} + +static mdns_rsrc* mdns_match(const char* qstr, u16_t qType) +{ + mdns_rsrc* rp = gDictP; + while (rp != NULL) { + if (rp->rType==qType || qType==DNS_RRTYPE_ANY) { + if (strcasecmp(rp->rData,qstr)==0) { + #ifdef qDebugLog + printf(" - matched '%s' %s\n",qstr,mdns_qrtype(rp->rType)); + #endif + break; + } + } + rp = rp->rNext; + } + return rp; +} + +static int mdns_add_to_answer(mdns_rsrc* rsrcP, u8_t* resp, int respLen) +// Create answer RR and append to resp[respLen], return new length +{ + // Key is stored as C str, convert to labels + respLen += mdns_str2labels(rsrcP->rData, &resp[respLen], DNS_MSG_SIZE-respLen); + + // Answer fields: may be misaligned, so build and memcpy + struct mdns_answer ans; + ans.type = htons(rsrcP->rType); + ans.class = htons(DNS_RRCLASS_IN); + ans.ttl = htonl(rsrcP->rTTL); + ans.len = htons(rsrcP->rDataSize); + memcpy(&resp[respLen], &ans, SIZEOF_DNS_ANSWER); + respLen += SIZEOF_DNS_ANSWER; + + // Data for this key + memcpy(&resp[respLen], &rsrcP->rData[rsrcP->rKeySize], rsrcP->rDataSize); + respLen += rsrcP->rDataSize; + + return respLen; +} + +//--------------------------------------------------------------------------- + +static void mdns_send_mcast(u8_t* msgP, int nBytes) +// Send UDP to multicast address +{ + struct pbuf* p; + err_t err; + + p = pbuf_alloc(PBUF_TRANSPORT, nBytes, PBUF_RAM); + if (p) { + memcpy(p->payload, msgP, nBytes); + err = udp_sendto(gMDNS_pcb, p, &gMulticastAddr, DNS_MDNS_PORT); + if (err==ERR_OK) { + #ifdef qDebugLog + printf(" - responded with %d bytes err %d\n",nBytes,err); + #endif + } else + printf(">>> mdns_send failed %d\n",err); + pbuf_free(p); + } else + printf(">>> mdns_send: alloc failed[%d]\n",nBytes); +} + +static void mdns_reply(struct mdns_hdr* hdrP) +// Message has passed tests, may want to send an answer +{ + int i, nquestions, respLen; + struct mdns_hdr* rHdr; + mdns_rsrc* extra; + u8_t* qBase = (u8_t*)hdrP; + u8_t* qp; + u8_t* mdns_response; + + mdns_response = malloc(DNS_MSG_SIZE); + if (mdns_response==NULL) { + printf(">>> mdns_reply could not alloc %d\n",DNS_MSG_SIZE); + return; + } + + // Build response header + rHdr = (struct mdns_hdr*) mdns_response; + rHdr->id = hdrP->id; + rHdr->flags1 = DNS_FLAG1_RESP + DNS_FLAG1_AUTH; + rHdr->flags2 = 0; + rHdr->numquestions = 0; + rHdr->numanswers = 0; + rHdr->numauthrr = 0; + rHdr->numextrarr = 0; + respLen = SIZEOF_DNS_HDR; + + extra = NULL; + qp = qBase + SIZEOF_DNS_HDR; + nquestions = htons(hdrP->numquestions); + + for (i=0; inumanswers = htons( htons(rHdr->numanswers) + 1 ); + // Extra RR logic: if SRV follows PTR, or A follows SRV, volunteer it in extraRR + // Not required, but could do more here, see RFC6763 s12 + if (qType==DNS_RRTYPE_PTR) { + if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_SRV) + extra = rsrcP->rNext; + } else if (qType==DNS_RRTYPE_SRV) { + if (rsrcP->rNext && rsrcP->rNext->rType==DNS_RRTYPE_A) + extra = rsrcP->rNext; + } + } + } + } // for nQuestions + + if (respLen > SIZEOF_DNS_HDR) { + if (extra) { + respLen = mdns_add_to_answer(extra, mdns_response, respLen); + rHdr->numextrarr = htons( htons(rHdr->numextrarr) + 1 ); + } + mdns_send_mcast(mdns_response,respLen); + } + free(mdns_response); +} + +static void mdns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +// Callback from udp_recv +{ + UNUSED_ARG(pcb); + UNUSED_ARG(port); + + u8_t* mdns_payload; + int plen; + + // Sanity checks on size + plen = p->tot_len; + if (plen > DNS_MSG_SIZE) { + printf(">>> mdns_recv: pbuf too big\n"); + } else if (plen < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + 1 + SIZEOF_DNS_ANSWER + 1)) { + printf(">>> mdns_recv: pbuf too small\n"); + } else { + #ifdef qLogIncoming + printf("\n\nmDNS got %d bytes from %d.%d.%d.%d\n",plen, ip4_addr1(addr), ip4_addr2(addr), ip4_addr3(addr), ip4_addr4(addr)); + #endif + mdns_payload = malloc(plen); + if (!mdns_payload) + printf(">>> mdns_recv, could not alloc %d\n",plen); + else { + if (pbuf_copy_partial(p, mdns_payload, plen, 0) == plen) { + struct mdns_hdr* hdrP = (struct mdns_hdr*) mdns_payload; + + #ifdef qLogAllTraffic + mdns_print_msg(mdns_payload, plen); + #endif + + if ( (hdrP->flags1 & (DNS_FLAG1_RESP + DNS_FLAG1_OPMASK + DNS_FLAG1_TRUNC) ) == 0 + && hdrP->numquestions > 0 ) + mdns_reply(hdrP); + } + free(mdns_payload); + } + } + pbuf_free(p); +} + +static void mdns_start() +// If we are in station mode and have an IP address, start a multicast UDP receive +{ + struct ip_info ipInfo; + err_t err; + + if (sdk_wifi_get_opmode() != STATION_MODE) { + printf(">>> mDNS_start: wifi opmode not station\n"); + return; + } + + if (!sdk_wifi_get_ip_info(STATION_IF,&ipInfo)) { + printf(">>> mDNS_start: no IP addr\n"); + return; + } + + mdns_update_ipaddr(&ipInfo); + + // Start IGMP on the netif for our interface: this isn't done for us + struct netif* nfp = netif_list; + while (nfp!=NULL) { + if ( ip_addr_cmp(&ipInfo.ip, &(nfp->ip_addr)) ) { + if (!(nfp->flags & NETIF_FLAG_IGMP)) { + nfp->flags |= NETIF_FLAG_IGMP; + err = igmp_start(nfp); + if (err != ERR_OK) { + printf(">>> mDNS_start: igmp_start on %c%c failed %d\n",nfp->name[0], nfp->name[1],err); + return; + } + } + } + nfp = nfp->next; + } + + gMDNS_pcb = udp_new(); + if (!gMDNS_pcb) { + printf(">>> mDNS_start: udp_new failed\n"); + return; + } + + if ((err=igmp_joingroup(&ipInfo.ip, &gMulticastAddr)) != ERR_OK) { + printf(">>> mDNS_start: igmp_join failed %d\n",err); + return; + } + + if ((err=udp_bind(gMDNS_pcb, IP_ADDR_ANY, DNS_MDNS_PORT)) != ERR_OK) { + printf(">>> mDNS_start: udp_bind failed %d\n",err); + return; + } + + udp_recv(gMDNS_pcb, mdns_recv, NULL); +} + +static void mdns_close() +{ + udp_remove(gMDNS_pcb); + gMDNS_pcb = NULL; + #ifdef qDebugLog + printf("Closing mDNS\n"); + #endif +} + +static void mdns_task(void *pvParameters) +{ + uint8_t hasIP = 0; + uint8_t status; + UNUSED_ARG(pvParameters); + + ipaddr_aton(DNS_MULTICAST_ADDRESS, &gMulticastAddr); + // Wait until we have joined AP and are assigned an IP + while (1) { + status = (sdk_wifi_station_get_connect_status() == STATION_GOT_IP); + if (status != hasIP) { + if (status) mdns_start(); + else mdns_close(); + hasIP = status; + } + vTaskDelayMs(status ? 1000 : 100); + } +} + +void mdns_init() +{ + #if LWIP_IGMP + xTaskCreate(mdns_task, "MDNS", kMDNSStackSize, NULL, 2, NULL); + #else + #error "LWIP_IGMP needs to be defined in lwipopts.h" + #endif +} diff --git a/extras/mdnsresponder/mdnsresponder.h b/extras/mdnsresponder/mdnsresponder.h new file mode 100644 index 0000000..2dd8c76 --- /dev/null +++ b/extras/mdnsresponder/mdnsresponder.h @@ -0,0 +1,52 @@ +#ifndef __MDNSRESPONDER_H__ +#define __MDNSRESPONDER_H__ + +/* + * Basic multicast DNS responder + * + * Advertises the IP address, port, and characteristics of a service to other devices using multicast DNS on the same LAN, + * so they can find devices with addresses dynamically allocated by DHCP. See avahi, Bonjour, etc + * See RFC6762, RFC6763 + * + * This sample code is in the public domain. + * + * by M J A Hamel 2016 + */ + + +// Starts the mDNS responder task, call first +void mdns_init(); + +// Build and advertise an appropriate linked set of PTR/TXT/SRV/A records for the parameters provided +// This is a simple canned way to build a set of records for a single service that will +// be advertised whenever the device is given an IP address by WiFi + +typedef enum { + mdns_TCP, + mdns_UDP, + mdns_Browsable // see RFC6763:11 - adds a standard record that lets browsers find the service without needing to know its name +} mdns_flags; + +void mdns_add_facility( const char* instanceName, // Short user-friendly instance name, should NOT include serial number/MAC/etc + const char* serviceName, // Must be registered, _name, (see RFC6335 5.1 & 5.2) + const char* addText, // Should be =, or "" if unused (see RFC6763 6.3) + mdns_flags flags, // TCP or UDP plus browsable + u16_t onPort, // port number + u32_t ttl // time-to-live, seconds + ); + + +// Low-level RR builders for rolling your own +void mdns_add_PTR(const char* rKey, u32_t ttl, const char* nameStr); +void mdns_add_SRV(const char* rKey, u32_t ttl, u16_t rPort, const char* targname); +void mdns_add_TXT(const char* rKey, u32_t ttl, const char* txtStr); +void mdns_add_A (const char* rKey, u32_t ttl, struct ip_addr addr); + +/* Sample usage, advertising a secure web service + + mdns_init(); + mdns_add_facility("Fluffy", "_https", "Zoom=1", mdns_TCP+mdns_Browsable, 443, 600); + +*/ + +#endif diff --git a/extras/ms561101ba03/ms561101ba03.c b/extras/ms561101ba03/ms561101ba03.c index 282b21b..d88f488 100644 --- a/extras/ms561101ba03/ms561101ba03.c +++ b/extras/ms561101ba03/ms561101ba03.c @@ -8,7 +8,6 @@ * BSD Licensed as described in the file LICENSE */ #include "ms561101ba03.h" -#include #include #include "FreeRTOS.h" #include "task.h" @@ -26,60 +25,67 @@ */ #define CONVERSION_TIME 20 / portTICK_PERIOD_MS // milliseconds -static inline bool reset(uint8_t addr) +static inline int reset(i2c_dev_t* i2c_dev) { uint8_t buf[1] = { RESET }; - return i2c_slave_write(addr, buf, 1); + return i2c_slave_write(i2c_dev->bus, i2c_dev->addr, NULL, buf, 1); } static inline bool read_prom(ms561101ba03_t *dev) { uint8_t tmp[2] = { 0, 0 }; + uint8_t reg = 0xA2 ; - if (!i2c_slave_read(dev->addr, 0xA2, tmp, 2)) + if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2)) return false; dev->config_data.sens = tmp[0] << 8 | tmp[1]; - if (!i2c_slave_read(dev->addr, 0xA4, tmp, 2)) + reg = 0xA4 ; + if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2)) return false; dev->config_data.off = tmp[0] << 8 | tmp[1]; - if (!i2c_slave_read(dev->addr, 0xA6, tmp, 2)) + reg = 0xA6 ; + if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2)) return false; dev->config_data.tcs = tmp[0] << 8 | tmp[1]; - if (!i2c_slave_read(dev->addr, 0xA8, tmp, 2)) + reg = 0xA8 ; + if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2)) return false; dev->config_data.tco = tmp[0] << 8 | tmp[1]; - if (!i2c_slave_read(dev->addr, 0xAA, tmp, 2)) + reg = 0xAA ; + if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2)) return false; dev->config_data.t_ref = tmp[0] << 8 | tmp[1]; - if (!i2c_slave_read(dev->addr, 0xAC, tmp, 2)) + reg = 0xAC ; + if (i2c_slave_read(dev->i2c_dev.bus, dev->i2c_dev.addr, ®, tmp, 2)) return false; dev->config_data.tempsens = tmp[0] << 8 | tmp[1]; return true; } -static inline bool start_pressure_conversion(ms561101ba03_t *dev) //D1 +static inline int start_pressure_conversion(ms561101ba03_t *dev) //D1 { uint8_t buf = CONVERT_D1 + dev->osr; - return i2c_slave_write(dev->addr, &buf, 1); + return i2c_slave_write(dev->i2c_dev.bus, dev->i2c_dev.addr, NULL, &buf, 1); } -static inline bool start_temperature_conversion(ms561101ba03_t *dev) //D2 +static inline int start_temperature_conversion(ms561101ba03_t *dev) //D2 { uint8_t buf = CONVERT_D2 + dev->osr; - return i2c_slave_write(dev->addr, &buf, 1); + return i2c_slave_write(dev->i2c_dev.bus, dev->i2c_dev.addr, NULL, &buf, 1); } -static inline bool read_adc(uint8_t addr, uint32_t *result) +static inline bool read_adc(i2c_dev_t* i2c_dev, uint32_t *result) { *result = 0; uint8_t tmp[3]; - if (!i2c_slave_read(addr, 0x00, tmp, 3)) + uint8_t reg = 0x00 ; + if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, ®, tmp, 3)) return false; *result = (tmp[0] << 16) | (tmp[1] << 8) | tmp[2]; @@ -132,12 +138,12 @@ static inline int32_t calc_p(uint32_t digital_pressure, int64_t sens, int64_t of static inline bool get_raw_temperature(ms561101ba03_t *dev, uint32_t *result) { - if (!start_temperature_conversion(dev)) + if (start_temperature_conversion(dev)) return false; vTaskDelay(CONVERSION_TIME); - if (!read_adc(dev->addr, result)) + if (!read_adc(&dev->i2c_dev, result)) return false; return true; @@ -145,12 +151,12 @@ static inline bool get_raw_temperature(ms561101ba03_t *dev, uint32_t *result) static inline bool get_raw_pressure(ms561101ba03_t *dev, uint32_t *result) { - if (!start_pressure_conversion(dev)) + if (start_pressure_conversion(dev)) return false; vTaskDelay(CONVERSION_TIME); - if (!read_adc(dev->addr, result)) + if (!read_adc(&dev->i2c_dev, result)) return false; return true; @@ -209,7 +215,7 @@ bool ms561101ba03_get_sensor_data(ms561101ba03_t *dev) bool ms561101ba03_init(ms561101ba03_t *dev) { // First of all we need to reset the chip - if (!reset(dev->addr)) + if (reset(&dev->i2c_dev)) return false; // Wait a bit for the device to reset vTaskDelay(CONVERSION_TIME); diff --git a/extras/ms561101ba03/ms561101ba03.h b/extras/ms561101ba03/ms561101ba03.h index d658be2..fb357e7 100644 --- a/extras/ms561101ba03/ms561101ba03.h +++ b/extras/ms561101ba03/ms561101ba03.h @@ -12,6 +12,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -60,7 +61,7 @@ typedef struct */ typedef struct { - uint8_t addr; //!< I2C address + i2c_dev_t i2c_dev; //!< I2C device settings ms561101ba03_osr_t osr; //!< Oversampling setting ms561101ba03_config_data_t config_data; //!< Device configuration, filled upon initalize ms561101ba03_result_t result; //!< Result, filled upon co diff --git a/extras/paho_mqtt_c/MQTTClient.c b/extras/paho_mqtt_c/MQTTClient.c index e8209ea..c2419c3 100644 --- a/extras/paho_mqtt_c/MQTTClient.c +++ b/extras/paho_mqtt_c/MQTTClient.c @@ -424,6 +424,8 @@ int mqtt_subscribe(mqtt_client_t* c, const char* topic, enum mqtt_qos qos, mqtt if (rc != 0x80) { int i; + + rc = MQTT_FAILURE; for (i = 0; i < MQTT_MAX_MESSAGE_HANDLERS; ++i) { if (c->messageHandlers[i].topicFilter == 0) diff --git a/extras/paho_mqtt_c/MQTTESP8266.c b/extras/paho_mqtt_c/MQTTESP8266.c index e7a14d9..a6f1e75 100644 --- a/extras/paho_mqtt_c/MQTTESP8266.c +++ b/extras/paho_mqtt_c/MQTTESP8266.c @@ -32,7 +32,7 @@ char mqtt_timer_expired(mqtt_timer_t* timer) { TickType_t now = xTaskGetTickCount(); int32_t left = timer->end_time - now; - return (left < 0); + return (left <= 0); } @@ -53,7 +53,7 @@ int mqtt_timer_left_ms(mqtt_timer_t* timer) { TickType_t now = xTaskGetTickCount(); int32_t left = timer->end_time - now; - return (left < 0) ? 0 : left / portTICK_PERIOD_MS; + return (left < 0) ? 0 : left * portTICK_PERIOD_MS; } @@ -72,9 +72,8 @@ int mqtt_esp_read(mqtt_network_t* n, unsigned char* buffer, int len, int timeou int rcvd = 0; FD_ZERO(&fdset); FD_SET(n->my_socket, &fdset); - // It seems tv_sec actually means FreeRTOS tick - tv.tv_sec = timeout_ms / portTICK_PERIOD_MS; - tv.tv_usec = 0; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; rc = select(n->my_socket + 1, &fdset, 0, 0, &tv); if ((rc > 0) && (FD_ISSET(n->my_socket, &fdset))) { @@ -97,9 +96,8 @@ int mqtt_esp_write(mqtt_network_t* n, unsigned char* buffer, int len, int timeo FD_ZERO(&fdset); FD_SET(n->my_socket, &fdset); - // It seems tv_sec actually means FreeRTOS tick - tv.tv_sec = timeout_ms / portTICK_PERIOD_MS; - tv.tv_usec = 0; + tv.tv_sec = timeout_ms / 1000; + tv.tv_usec = (timeout_ms % 1000) * 1000; rc = select(n->my_socket + 1, 0, &fdset, 0, &tv); if ((rc > 0) && (FD_ISSET(n->my_socket, &fdset))) { diff --git a/extras/pca9685/pca9685.c b/extras/pca9685/pca9685.c index 0e116e2..6b04c31 100644 --- a/extras/pca9685/pca9685.c +++ b/extras/pca9685/pca9685.c @@ -7,7 +7,6 @@ */ #include "pca9685.h" -#include #include #define REG_MODE1 0x00 @@ -59,33 +58,32 @@ inline static uint32_t round_div(uint32_t x, uint32_t y) return (x + y / 2) / y; } -inline static void write_reg(uint8_t addr, uint8_t reg, uint8_t val) +inline static void write_reg(i2c_dev_t* dev, uint8_t reg, uint8_t val) { - uint8_t data[2] = { reg, val }; - if (!i2c_slave_write(addr, data, 2)) - debug("Could not write 0x%02x to 0x%02x, addr = 0x%02x", reg, val, addr); + if (i2c_slave_write(dev->bus, dev->addr, ®, &val, 1)) + debug("Could not write 0x%02x to 0x%02x, bus %u, addr = 0x%02x", reg, val, dev->bus, dev->addr); } -inline static uint8_t read_reg(uint8_t addr, uint8_t reg) +inline static uint8_t read_reg(i2c_dev_t* dev, uint8_t reg) { uint8_t res = 0; - if (!i2c_slave_read(addr, reg, &res, 1)) - debug("Could not read from 0x%02x, addr = 0x%02x", reg, addr); + if (i2c_slave_read(dev->bus, dev->addr, ®, &res, 1)) + debug("Could not read from 0x%02x, bus %u, addr = 0x%02x", reg, dev->bus, dev->addr); return res; } -inline static void update_reg(uint8_t addr, uint8_t reg, uint8_t mask, uint8_t val) +inline static void update_reg(i2c_dev_t* dev, uint8_t reg, uint8_t mask, uint8_t val) { - write_reg(addr, reg, (read_reg(addr, reg) & ~mask) | val); + write_reg(dev, reg, (read_reg(dev, reg) & ~mask) | val); } -void pca9685_init(uint8_t addr) +void pca9685_init(i2c_dev_t* dev) { // Enable autoincrement - update_reg(addr, REG_MODE1, MODE1_AI, MODE1_AI); + update_reg(dev, REG_MODE1, MODE1_AI, MODE1_AI); } -bool pca9685_set_subaddr(uint8_t addr, uint8_t num, uint8_t subaddr, bool enable) +bool pca9685_set_subaddr(i2c_dev_t* dev, uint8_t num, uint8_t subaddr, bool enable) { if (num > MAX_SUBADDR) { @@ -93,63 +91,63 @@ bool pca9685_set_subaddr(uint8_t addr, uint8_t num, uint8_t subaddr, bool enable return false; } - write_reg(addr, REG_SUBADR1 + num, subaddr << 1); + write_reg(dev, REG_SUBADR1 + num, subaddr << 1); uint8_t mask = 1 << (MODE1_SUB_BIT - num); - update_reg(addr, REG_MODE1, mask, enable ? mask : 0); + update_reg(dev, REG_MODE1, mask, enable ? mask : 0); return true; } -bool pca9685_is_sleeping(uint8_t addr) +bool pca9685_is_sleeping(i2c_dev_t* dev) { - return (read_reg(addr, REG_MODE1) & MODE1_SLEEP) != 0; + return (read_reg(dev, REG_MODE1) & MODE1_SLEEP) != 0; } -void pca9685_sleep(uint8_t addr, bool sleep) +void pca9685_sleep(i2c_dev_t* dev, bool sleep) { - update_reg(addr, REG_MODE1, MODE1_SLEEP, sleep ? MODE1_SLEEP : 0); + update_reg(dev, REG_MODE1, MODE1_SLEEP, sleep ? MODE1_SLEEP : 0); if (!sleep) sdk_os_delay_us(WAKEUP_DELAY_US); } -void pca9685_restart(uint8_t addr) +void pca9685_restart(i2c_dev_t* dev) { - uint8_t mode = read_reg(addr, REG_MODE1); + uint8_t mode = read_reg(dev, REG_MODE1); if (mode & MODE1_RESTART) { - write_reg(addr, REG_MODE1, mode & ~MODE1_SLEEP); + write_reg(dev, REG_MODE1, mode & ~MODE1_SLEEP); sdk_os_delay_us(WAKEUP_DELAY_US); } - write_reg(addr, REG_MODE1, (mode & ~MODE1_SLEEP) | MODE1_RESTART); + write_reg(dev, REG_MODE1, (mode & ~MODE1_SLEEP) | MODE1_RESTART); } -bool pca9685_is_output_inverted(uint8_t addr) +bool pca9685_is_output_inverted(i2c_dev_t* dev) { - return (read_reg(addr, REG_MODE2) & MODE2_INVRT) != 0; + return (read_reg(dev, REG_MODE2) & MODE2_INVRT) != 0; } -void pca9685_set_output_inverted(uint8_t addr, bool inverted) +void pca9685_set_output_inverted(i2c_dev_t* dev, bool inverted) { - update_reg(addr, REG_MODE2, MODE2_INVRT, inverted ? MODE2_INVRT : 0); + update_reg(dev, REG_MODE2, MODE2_INVRT, inverted ? MODE2_INVRT : 0); } -bool pca9685_get_output_open_drain(uint8_t addr) +bool pca9685_get_output_open_drain(i2c_dev_t* dev) { - return (read_reg(addr, REG_MODE2) & MODE2_OUTDRV) == 0; + return (read_reg(dev, REG_MODE2) & MODE2_OUTDRV) == 0; } -void pca9685_set_output_open_drain(uint8_t addr, bool open_drain) +void pca9685_set_output_open_drain(i2c_dev_t* dev, bool open_drain) { - update_reg(addr, REG_MODE2, MODE2_OUTDRV, open_drain ? 0 : MODE2_OUTDRV); + update_reg(dev, REG_MODE2, MODE2_OUTDRV, open_drain ? 0 : MODE2_OUTDRV); } -uint8_t pca9685_get_prescaler(uint8_t addr) +uint8_t pca9685_get_prescaler(i2c_dev_t* dev) { - return read_reg(addr, REG_PRE_SCALE); + return read_reg(dev, REG_PRE_SCALE); } -bool pca9685_set_prescaler(uint8_t addr, uint8_t prescaler) +bool pca9685_set_prescaler(i2c_dev_t* dev, uint8_t prescaler) { if (prescaler < MIN_PRESCALER) { @@ -157,18 +155,18 @@ bool pca9685_set_prescaler(uint8_t addr, uint8_t prescaler) return false; } - pca9685_sleep(addr, true); - write_reg(addr, REG_PRE_SCALE, prescaler); - pca9685_sleep(addr, false); + pca9685_sleep(dev, true); + write_reg(dev, REG_PRE_SCALE, prescaler); + pca9685_sleep(dev, false); return true; } -uint16_t pca9685_get_pwm_frequency(uint8_t addr) +uint16_t pca9685_get_pwm_frequency(i2c_dev_t* dev) { - return INTERNAL_FREQ / ((uint32_t)4096 * (read_reg(addr, REG_PRE_SCALE) + 1)); + return INTERNAL_FREQ / ((uint32_t)4096 * (read_reg(dev, REG_PRE_SCALE) + 1)); } -bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq) +bool pca9685_set_pwm_frequency(i2c_dev_t* dev, uint16_t freq) { uint16_t prescaler = round_div(INTERNAL_FREQ, (uint32_t)4096 * freq) - 1; if (prescaler < MIN_PRESCALER || prescaler > MAX_PRESCALER) @@ -177,32 +175,32 @@ bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq) return false; } - return pca9685_set_prescaler(addr, prescaler); + return pca9685_set_prescaler(dev, prescaler); } -void pca9685_set_pwm_value(uint8_t addr, uint8_t channel, uint16_t val) +void pca9685_set_pwm_value(i2c_dev_t* dev, uint8_t channel, uint16_t val) { uint8_t reg = channel > MAX_CHANNEL ? REG_ALL_LED : REG_LED_N(channel); if (val == 0) { // Full off - write_reg(addr, reg + OFFS_REG_LED_OFF, LED_FULL_ON_OFF); + write_reg(dev, reg + OFFS_REG_LED_OFF, LED_FULL_ON_OFF); } else if (val < 4096) { // Normal - uint8_t buf[5] = { reg, 0, 0, val, val >> 8 }; - i2c_slave_write(addr, buf, 5); + uint8_t buf[4] = { 0, 0, val, val >> 8 }; + i2c_slave_write(dev->bus, dev->addr, ®, buf, 4); } else { // Full on - write_reg(addr, reg + OFFS_REG_LED_ON, LED_FULL_ON_OFF); + write_reg(dev, reg + OFFS_REG_LED_ON, LED_FULL_ON_OFF); } } -bool pca9685_set_pwm_values(uint8_t addr, uint8_t first_ch, uint8_t channels, const uint16_t *values) +bool pca9685_set_pwm_values(i2c_dev_t* dev, uint8_t first_ch, uint8_t channels, const uint16_t *values) { if (channels == 0 || first_ch + channels - 1 > MAX_CHANNEL) { @@ -211,7 +209,7 @@ bool pca9685_set_pwm_values(uint8_t addr, uint8_t first_ch, uint8_t channels, co } for (uint8_t i = 0; i < channels; i ++) - pca9685_set_pwm_value(addr, first_ch + i, values [i]); + pca9685_set_pwm_value(dev, first_ch + i, values [i]); return true; } diff --git a/extras/pca9685/pca9685.h b/extras/pca9685/pca9685.h index 0ee0000..a92b964 100644 --- a/extras/pca9685/pca9685.h +++ b/extras/pca9685/pca9685.h @@ -10,6 +10,7 @@ #include #include +#include #ifdef __cplusplus extern "C" @@ -22,7 +23,7 @@ extern "C" * Init device * @param addr Device address */ -void pca9685_init(uint8_t addr); +void pca9685_init(i2c_dev_t* dev); /** * Setup device subaddress (see section 7.3.6 if the datasheet) @@ -32,62 +33,62 @@ void pca9685_init(uint8_t addr); * @param enable True to enable subaddress, false to disable * @return False if error occured */ -bool pca9685_set_subaddr(uint8_t addr, uint8_t num, uint8_t subaddr, bool enable); +bool pca9685_set_subaddr(i2c_dev_t* dev, uint8_t num, uint8_t subaddr, bool enable); /** * Restart device (see section 7.3.1.1 of the datasheet) * @param addr Device address */ -void pca9685_restart(uint8_t addr); +void pca9685_restart(i2c_dev_t* dev); /** * Check if device is in sleep mode * @param addr Device address * @return True if device is sleeping */ -bool pca9685_is_sleeping(uint8_t addr); +bool pca9685_is_sleeping(i2c_dev_t* dev); /** * Switch device to low-power mode or wake it up. * @param addr Device address * @param sleep True for sleep mode, false for wake up */ -void pca9685_sleep(uint8_t addr, bool sleep); +void pca9685_sleep(i2c_dev_t* dev, bool sleep); /** * Get logic inversion of the outputs * @param addr Device address * @return True if outputs are inverted, false otherwise */ -bool pca9685_is_output_inverted(uint8_t addr); +bool pca9685_is_output_inverted(i2c_dev_t* dev); /** * Logically invert outputs (see section 7.7 of the datasheet) * @param addr Device address * @param inverted True for inverted outputs */ -void pca9685_set_output_inverted(uint8_t addr, bool inverted); +void pca9685_set_output_inverted(i2c_dev_t* dev, bool inverted); /** * Get outputs mode * @param addr Device address * @return True if outputs are in open drain mode */ -bool pca9685_get_output_open_drain(uint8_t addr); +bool pca9685_get_output_open_drain(i2c_dev_t* dev); /** * Set outputs mode * @param addr Device address * @param open_drain True to set open drain mode, false to normal mode */ -void pca9685_set_output_open_drain(uint8_t addr, bool open_drain); +void pca9685_set_output_open_drain(i2c_dev_t* dev, bool open_drain); /** * Get current PWM frequency prescaler. * @param addr Device address * @return Frequency prescaler */ -uint8_t pca9685_get_prescaler(uint8_t addr); +uint8_t pca9685_get_prescaler(i2c_dev_t* dev); /** * Set PWM frequency prescaler. @@ -95,14 +96,14 @@ uint8_t pca9685_get_prescaler(uint8_t addr); * @param prescaler Prescaler value * @return False if error occured */ -bool pca9685_set_prescaler(uint8_t addr, uint8_t prescaler); +bool pca9685_set_prescaler(i2c_dev_t* dev, uint8_t prescaler); /** * Get current PWM frequency * @param addr Device address * @return PWM frequency, Hz */ -uint16_t pca9685_get_pwm_frequency(uint8_t addr); +uint16_t pca9685_get_pwm_frequency(i2c_dev_t* dev); /** * Set PWM frequency @@ -110,7 +111,7 @@ uint16_t pca9685_get_pwm_frequency(uint8_t addr); * @param freq PWM frequency, Hz * @return False if error occured */ -bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq); +bool pca9685_set_pwm_frequency(i2c_dev_t* dev, uint16_t freq); /** * Set PWM value on output channel @@ -118,7 +119,7 @@ bool pca9685_set_pwm_frequency(uint8_t addr, uint16_t freq); * @param channel Channel number, 0..15 or >15 for all channels * @param val PWM value, 0..4096 */ -void pca9685_set_pwm_value(uint8_t addr, uint8_t channel, uint16_t val); +void pca9685_set_pwm_value(i2c_dev_t* dev, uint8_t channel, uint16_t val); /** * Set PWM values on output channels @@ -128,7 +129,7 @@ void pca9685_set_pwm_value(uint8_t addr, uint8_t channel, uint16_t val); * @param values Array of the channel values, each 0..4096 * @return False if error occured */ -bool pca9685_set_pwm_values(uint8_t addr, uint8_t first_ch, uint8_t channels, const uint16_t *values); +bool pca9685_set_pwm_values(i2c_dev_t* dev, uint8_t first_ch, uint8_t channels, const uint16_t *values); #ifdef __cplusplus } diff --git a/extras/pcf8574/pcf8574.c b/extras/pcf8574/pcf8574.c index e92ebc8..ff9a92c 100644 --- a/extras/pcf8574/pcf8574.c +++ b/extras/pcf8574/pcf8574.c @@ -1,54 +1,46 @@ #include "pcf8574.h" -#include -uint8_t pcf8574_port_read(uint8_t addr) +uint8_t pcf8574_port_read(i2c_dev_t* dev) { - i2c_start(); - uint8_t res = i2c_write((addr << 1) | 1) ? i2c_read(1) : 0; - i2c_stop(); + uint8_t res; + if (i2c_slave_read(dev->bus, dev->addr, NULL, &res, 1)) + return 0; return res; } -size_t pcf8574_port_read_buf(uint8_t addr, void *buf, size_t len) +size_t pcf8574_port_read_buf(i2c_dev_t* dev, void *buf, size_t len) { if (!len || !buf) return 0; uint8_t *_buf = (uint8_t *)buf; - i2c_start(); - if (!i2c_write((addr << 1) | 1)) return 0; - for (size_t i = 0; i < len; i++) - *_buf++ = i2c_read(i == len - 1); - i2c_stop(); + if (i2c_slave_read(dev->bus, dev->addr, NULL, _buf, len)) + return 0; return len; } -size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len) +size_t pcf8574_port_write_buf(const i2c_dev_t* dev, void *buf, size_t len) { if (!len || !buf) return 0; uint8_t *_buf = (uint8_t *)buf; - i2c_start(); - if (!i2c_write(addr << 1)) return 0; - for (size_t i = 0; i < len; i++) - i2c_write(*_buf++); + if (i2c_slave_write(dev->bus, dev->addr, NULL, _buf, len)) + return 0; return len; } -void pcf8574_port_write(uint8_t addr, uint8_t value) +void pcf8574_port_write(const i2c_dev_t* dev, uint8_t value) { - i2c_start(); - if (i2c_write(addr << 1)) i2c_write(value); - i2c_stop(); + i2c_slave_write(dev->bus, dev->addr, NULL, &value, 1); } -bool pcf8574_gpio_read(uint8_t addr, uint8_t num) +bool pcf8574_gpio_read(i2c_dev_t* dev, uint8_t num) { - return (bool)((pcf8574_port_read(addr) >> num) & 1); + return (bool)((pcf8574_port_read(dev) >> num) & 1); } -void pcf8574_gpio_write(uint8_t addr, uint8_t num, bool value) +void pcf8574_gpio_write(i2c_dev_t* dev, uint8_t num, bool value) { uint8_t bit = (uint8_t)value << num; uint8_t mask = ~(1 << num); - pcf8574_port_write (addr, (pcf8574_port_read(addr) & mask) | bit); + pcf8574_port_write (dev, (pcf8574_port_read(dev) & mask) | bit); } diff --git a/extras/pcf8574/pcf8574.h b/extras/pcf8574/pcf8574.h index c14e25f..84b6ce0 100644 --- a/extras/pcf8574/pcf8574.h +++ b/extras/pcf8574/pcf8574.h @@ -8,6 +8,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" @@ -19,7 +20,7 @@ extern "C" * \param addr I2C register address (0b0100 for PCF8574) * \return 8-bit GPIO port value */ -uint8_t pcf8574_port_read(uint8_t addr); +uint8_t pcf8574_port_read(i2c_dev_t* dev); /** * \brief Continiously read GPIO port values to buffer @@ -28,14 +29,14 @@ uint8_t pcf8574_port_read(uint8_t addr); * @param len Buffer length * @return Number of bytes read */ -size_t pcf8574_port_read_buf(uint8_t addr, void *buf, size_t len); +size_t pcf8574_port_read_buf(i2c_dev_t* dev, void *buf, size_t len); /** * \brief Write value to GPIO port * \param addr I2C register address (0b0100 for PCF8574) * \param value GPIO port value */ -void pcf8574_port_write(uint8_t addr, uint8_t value); +void pcf8574_port_write(const i2c_dev_t* dev, uint8_t value); /** * \brief Continiously write GPIO values to GPIO port @@ -44,7 +45,7 @@ void pcf8574_port_write(uint8_t addr, uint8_t value); * @param len Buffer length * @return Number of bytes written */ -size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len); +size_t pcf8574_port_write_buf(const i2c_dev_t* dev, void *buf, size_t len); /** * \brief Read input value of a GPIO pin @@ -52,7 +53,7 @@ size_t pcf8574_port_write_buf(uint8_t addr, void *buf, size_t len); * \param num pin number (0..7) * \return GPIO pin value */ -bool pcf8574_gpio_read(uint8_t addr, uint8_t num); +bool pcf8574_gpio_read(i2c_dev_t* dev, uint8_t num); /** * \brief Set GPIO pin output @@ -62,7 +63,7 @@ bool pcf8574_gpio_read(uint8_t addr, uint8_t num); * \param num pin number (0..7) * \param value true for high level */ -void pcf8574_gpio_write(uint8_t addr, uint8_t num, bool value); +void pcf8574_gpio_write(i2c_dev_t* dev, uint8_t num, bool value); #ifdef __cplusplus } diff --git a/extras/pcf8591/component.mk b/extras/pcf8591/component.mk new file mode 100644 index 0000000..5e09035 --- /dev/null +++ b/extras/pcf8591/component.mk @@ -0,0 +1,6 @@ +# Component makefile for extras/pcf8591 + +INC_DIRS += $(pcf8591_ROOT).. +pcf8591_SRC_DIR = $(pcf8591_ROOT) + +$(eval $(call component_compile_rules,pcf8591)) diff --git a/extras/pcf8591/pcf8591.c b/extras/pcf8591/pcf8591.c new file mode 100644 index 0000000..ba06a5e --- /dev/null +++ b/extras/pcf8591/pcf8591.c @@ -0,0 +1,20 @@ +#include +#include + +#include "pcf8591.h" + +/** + * CAUTION: PLEASE SET LOW FREQUENCY + */ + +#define PCF8591_CTRL_REG_READ 0x03 + +uint8_t pcf8591_read(i2c_dev_t* dev, uint8_t analog_pin) +{ + uint8_t res = 0; + uint8_t control_reg = PCF8591_CTRL_REG_READ & analog_pin; + + i2c_slave_read(dev->bus, dev->addr, &control_reg, &res, 1); + + return res; +} diff --git a/extras/pcf8591/pcf8591.h b/extras/pcf8591/pcf8591.h new file mode 100644 index 0000000..5327323 --- /dev/null +++ b/extras/pcf8591/pcf8591.h @@ -0,0 +1,44 @@ +/** + * Driver for 8-bit analog-to-digital conversion and + * an 8-bit digital-to-analog conversion PCF8591 + * + * Part of esp-open-rtos + * Copyright (C) 2017 Pham Ngoc Thanh + * BSD Licensed as described in the file LICENSE + */ +#ifndef _EXTRAS_PCF8591_H_ +#define _EXTRAS_PCF8591_H_ + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * CAUTION: PLEASE SET I2C_FREQUENCY_400K IS 'false' IN 'i2c.h' FILE + */ + +#define PCF8591_DEFAULT_ADDRESS 0x48 + +void pcf8591_init(void); //FIXME : library incomplete ? + +/** + * Read input value of an analog pin. + * @param[in] addr Pointer to device + * @param[in] analog_pin pin number: + * 0 - AIN0 + * 1 - AIN1 + * 2 - AIN2 + * 3 - AIN3 + * @return analog value + */ +uint8_t pcf8591_read(i2c_dev_t* dev, uint8_t analog_pin); + + +#ifdef __cplusplus +} +#endif + +#endif /* _EXTRAS_PCF8591_H_ */ diff --git a/extras/pwm/pwm.c b/extras/pwm/pwm.c index 338dff0..3fbc8a4 100644 --- a/extras/pwm/pwm.c +++ b/extras/pwm/pwm.c @@ -29,7 +29,7 @@ typedef struct pwmInfoDefinition uint8_t running; uint16_t freq; - uint16_t dutyCicle; + uint16_t dutyCycle; /* private */ uint32_t _maxLoad; @@ -43,7 +43,7 @@ typedef struct pwmInfoDefinition static PWMInfo pwmInfo; -static void frc1_interrupt_handler(void) +static void frc1_interrupt_handler(void *arg) { uint8_t i = 0; bool out = true; @@ -66,7 +66,7 @@ static void frc1_interrupt_handler(void) pwmInfo._step = step; } -void pwm_init(uint8_t npins, uint8_t* pins) +void pwm_init(uint8_t npins, const uint8_t* pins) { /* Assert number of pins is correct */ if (npins > MAX_PWM_PINS) @@ -97,7 +97,7 @@ void pwm_init(uint8_t npins, uint8_t* pins) pwm_stop(); /* 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 */ pwmInfo.running = 0; @@ -127,10 +127,10 @@ void pwm_set_duty(uint16_t duty) { bool output; - pwmInfo.dutyCicle = duty; + pwmInfo.dutyCycle = duty; if (duty > 0 && duty < UINT16_MAX) { pwm_restart(); - return; + return; } // 0% and 100% duty cycle are special cases: constant output. @@ -139,7 +139,7 @@ void pwm_set_duty(uint16_t duty) output = (duty == UINT16_MAX); for (uint8_t i = 0; i < pwmInfo.usedPins; ++i) { - gpio_write(pwmInfo.pins[i].pin, output); + gpio_write(pwmInfo.pins[i].pin, output); } } @@ -154,7 +154,7 @@ void pwm_restart() void pwm_start() { - pwmInfo._onLoad = pwmInfo.dutyCicle * pwmInfo._maxLoad / UINT16_MAX; + pwmInfo._onLoad = pwmInfo.dutyCycle * pwmInfo._maxLoad / UINT16_MAX; pwmInfo._offLoad = pwmInfo._maxLoad - pwmInfo._onLoad; pwmInfo._step = PERIOD_ON; diff --git a/extras/pwm/pwm.h b/extras/pwm/pwm.h index 55b8761..e2e7d75 100644 --- a/extras/pwm/pwm.h +++ b/extras/pwm/pwm.h @@ -16,7 +16,7 @@ extern "C" { #endif -void pwm_init(uint8_t npins, uint8_t* pins); +void pwm_init(uint8_t npins, const uint8_t* pins); void pwm_set_freq(uint16_t freq); void pwm_set_duty(uint16_t duty); diff --git a/extras/sdio/sdio.c b/extras/sdio/sdio.c index 573d038..e601416 100644 --- a/extras/sdio/sdio.c +++ b/extras/sdio/sdio.c @@ -141,6 +141,8 @@ static uint16_t crc_ccitt(const uint8_t *data, size_t n) #define spi_skip_word() do { spi_read_byte(); spi_read_byte(); } while(0) #define spi_skip_dword() do { spi_read_byte(); spi_read_byte(); spi_read_byte(); spi_read_byte(); } while(0) +#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len)) + inline static uint16_t spi_write_word(uint16_t word) { return (spi_transfer_8(BUS, word >> 8) << 8) | spi_transfer_8(BUS, word); @@ -154,9 +156,10 @@ inline static void spi_read_bytes(uint8_t *dst, size_t size) static bool wait() { - uint32_t stop = sdk_system_get_time() + IO_TIMEOUT_US; + + uint32_t start = sdk_system_get_time(); while (spi_read_byte() != 0xff) - if (sdk_system_get_time() >= stop) + if (timeout_expired(start, IO_TIMEOUT_US)) return false; return true; } @@ -208,11 +211,11 @@ inline static sdio_error_t set_error(sdio_card_t *card, sdio_error_t err) static sdio_error_t read_data(sdio_card_t *card, uint8_t *dst, size_t size) { - uint32_t timeout = sdk_system_get_time() + IO_TIMEOUT_US; + uint32_t start = sdk_system_get_time(); while (true) { - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, IO_TIMEOUT_US)) return set_error(card, SDIO_ERR_TIMEOUT); uint8_t b = spi_read_byte(); @@ -269,7 +272,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div spi_set_settings(BUS, &s); gpio_enable(card->cs_pin, GPIO_OUTPUT); - uint32_t timeout = sdk_system_get_time() + INIT_TIMEOUT_US; + uint32_t start = sdk_system_get_time(); spi_cs_low(card); spi_cs_high(card); @@ -279,7 +282,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div // Set card to the SPI idle mode while (command(card, CMD0, 0) != BV(R1_IDLE_STATE)) { - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, INIT_TIMEOUT_US)) return set_error(card, SDIO_ERR_TIMEOUT); } @@ -300,7 +303,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div break; } - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, INIT_TIMEOUT_US)) return set_error(card, SDIO_ERR_TIMEOUT); } @@ -311,13 +314,13 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div { card->type = SDIO_TYPE_MMC; while (command(card, CMD1, 0)) - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, INIT_TIMEOUT_US)) return set_error(card, SDIO_ERR_TIMEOUT); } else { while (app_command(card, ACMD41, 0)) - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, INIT_TIMEOUT_US)) return set_error(card, SDIO_ERR_TIMEOUT); } @@ -328,7 +331,7 @@ sdio_error_t sdio_init(sdio_card_t *card, uint8_t cs_pin, uint32_t high_freq_div { // SD2 or SDHC while (app_command(card, ACMD41, BV(30)) != 0) - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, INIT_TIMEOUT_US)) return set_error(card, SDIO_ERR_TIMEOUT); } // read OCR diff --git a/extras/sntp/sntp.c b/extras/sntp/sntp.c index 48b2f14..c034df2 100644 --- a/extras/sntp/sntp.c +++ b/extras/sntp/sntp.c @@ -38,7 +38,7 @@ #include "sntp.h" -#include "lwip/timers.h" +#include "lwip/timeouts.h" #include "lwip/udp.h" #include "lwip/dns.h" #include "lwip/ip_addr.h" @@ -136,12 +136,12 @@ #define SNTP_STARTUP_DELAY 0 #endif -/** SNTP receive timeout - in milliseconds +/** SNTP receive timeout - in seconds * Also used as retry timeout - this shouldn't be too low. * Default is 3 seconds. */ #ifndef SNTP_RECV_TIMEOUT -#define SNTP_RECV_TIMEOUT 3000 +#define SNTP_RECV_TIMEOUT 3 #endif /** SNTP update delay - in milliseconds @@ -384,8 +384,8 @@ sntp_request(void *arg) /* bind to local address */ if (lwip_bind(sock, (struct sockaddr *)&local, sizeof(local)) == 0) { /* set recv timeout */ - timeout = SNTP_RECV_TIMEOUT; - lwip_setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)); + const struct timeval timeout = { SNTP_RECV_TIMEOUT, 0 }; + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); /* prepare SNTP request */ sntp_initialize_request(&sntpmsg); @@ -511,7 +511,7 @@ sntp_try_next_server(void* arg) /** UDP recv callback for the sntp pcb */ 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 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 */ static void -sntp_send_request(ip_addr_t *server_addr) +sntp_send_request(const ip_addr_t *server_addr) { struct pbuf* p; 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); /* 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 /* save server address to verify it in sntp_recv */ 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. */ 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(arg); @@ -730,10 +730,8 @@ int sntp_set_servers(char *server_url[], int num_servers) /* Allocate memory and copy servers */ for (i = 0; i < num_servers; i++) { - sntp_server_addresses[i] = malloc(strlen(server_url[i])); - if (sntp_server_addresses[i]) { - strcpy(sntp_server_addresses[i], server_url[i]); - } else { + sntp_server_addresses[i] = strdup(server_url[i]); + if (!sntp_server_addresses[i]) { sntp_num_servers = i; return -2; } diff --git a/extras/sntp/sntp_fun.c b/extras/sntp/sntp_fun.c index 7aaca20..96e8ffc 100644 --- a/extras/sntp/sntp_fun.c +++ b/extras/sntp/sntp_fun.c @@ -102,7 +102,7 @@ void sntp_update_rtc(time_t t, uint32_t us) { // DEBUG: Compute and print drift int64_t sntp_current = sntp_base + TIMER_COUNT - tim_ref; 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; cal = sdk_system_rtc_clock_cali_proc(); diff --git a/extras/softuart/LICENSE b/extras/softuart/LICENSE new file mode 100644 index 0000000..104c838 --- /dev/null +++ b/extras/softuart/LICENSE @@ -0,0 +1,23 @@ +The MIT License (MIT) + +Copyright (C) 2016 Bernhard Guillon +Copyright (c) 2015 plieningerweb + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/extras/softuart/component.mk b/extras/softuart/component.mk new file mode 100644 index 0000000..9517cf2 --- /dev/null +++ b/extras/softuart/component.mk @@ -0,0 +1,10 @@ +# Component makefile for extras/softuart + +# expected anyone using this driver includes it as 'softuart/softuart.h' +INC_DIRS += $(softuart_ROOT).. + +# args for passing into compile rule generation +softuart_SRC_DIR = $(softuart_ROOT) + +$(eval $(call component_compile_rules,softuart)) + diff --git a/extras/softuart/softuart.c b/extras/softuart/softuart.c new file mode 100644 index 0000000..7cfc0fc --- /dev/null +++ b/extras/softuart/softuart.c @@ -0,0 +1,270 @@ +/* + * Softuart + * + * Copyright (C) 2017 Ruslan V. Uss + * Copyright (C) 2016 Bernhard Guillon + * + * This code is based on Softuart from here [1] and reworked to + * fit into esp-open-rtos. + * + * it fits my needs to read the GY-GPS6MV2 module with 9600 8n1 + * + * Original Copyright: + * Copyright (c) 2015 plieningerweb + * + * MIT Licensed as described in the file LICENSE + * + * 1 https://github.com/plieningerweb/esp8266-software-uart + */ + +#include "softuart.h" +#include +#include +#include +#include + +//#define SOFTUART_DEBUG + +#ifdef SOFTUART_DEBUG +#define debug(fmt, ...) printf("%s: " fmt "\n", "SOFTUART", ## __VA_ARGS__) +#else +#define debug(fmt, ...) +#endif + +typedef struct +{ + char receive_buffer[SOFTUART_MAX_RX_BUFF]; + uint8_t receive_buffer_tail; + uint8_t receive_buffer_head; + uint8_t buffer_overflow; +} softuart_buffer_t; + +typedef struct +{ + uint8_t rx_pin, tx_pin; + uint32_t baudrate; + volatile softuart_buffer_t buffer; + uint16_t bit_time; +} softuart_t; + +static softuart_t uarts[SOFTUART_MAX_UARTS] = { { 0 } }; + +inline static int8_t find_uart_by_rx(uint8_t rx_pin) +{ + for (uint8_t i = 0; i < SOFTUART_MAX_UARTS; i++) + if (uarts[i].baudrate && uarts[i].rx_pin == rx_pin) return i; + + return -1; +} + +// GPIO interrupt handler +static void handle_rx(uint8_t gpio_num) +{ + // find uart + int8_t uart_no = find_uart_by_rx(gpio_num); + if (uart_no < 0) return; + + softuart_t *uart = uarts + uart_no; + + // Disable interrupt + gpio_set_interrupt(gpio_num, GPIO_INTTYPE_NONE, handle_rx); + + // Wait till start bit is half over so we can sample the next one in the center + sdk_os_delay_us(uart->bit_time / 2); + + // Now sample bits + uint8_t d = 0; + uint32_t start_time = 0x7FFFFFFF & sdk_system_get_time(); + + for (uint8_t i = 0; i < 8; i++) + { + while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * (i + 1)))) + { + // If system timer overflow, escape from while loop + if ((0x7FFFFFFF & sdk_system_get_time()) < start_time) + break; + } + // Shift d to the right + d >>= 1; + + // Read bit + if (gpio_read(uart->rx_pin)) + { + // If high, set msb of 8bit to 1 + d |= 0x80; + } + } + + // Store byte in buffer + // If buffer full, set the overflow flag and return + uint8_t next = (uart->buffer.receive_buffer_tail + 1) % SOFTUART_MAX_RX_BUFF; + if (next != uart->buffer.receive_buffer_head) + { + // save new data in buffer: tail points to where byte goes + uart->buffer.receive_buffer[uart->buffer.receive_buffer_tail] = d; // save new byte + uart->buffer.receive_buffer_tail = next; + } + else + { + uart->buffer.buffer_overflow = 1; + } + + // Wait for stop bit + sdk_os_delay_us(uart->bit_time); + + // Done, reenable interrupt + gpio_set_interrupt(uart->rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx); +} + +static bool check_uart_no(uint8_t uart_no) +{ + if (uart_no >= SOFTUART_MAX_UARTS) + { + debug("Invalid uart number %d, %d max", uart_no, SOFTUART_MAX_UARTS); + return false; + } + + return true; +} + +static bool check_uart_enabled(uint8_t uart_no) +{ + if (!uarts[uart_no].baudrate) + { + debug("Uart %d is disabled", uart_no); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +/// Public +/////////////////////////////////////////////////////////////////////////////// + +bool softuart_open(uint8_t uart_no, uint32_t baudrate, uint8_t rx_pin, uint8_t tx_pin) +{ + // do some checks + if (!check_uart_no(uart_no)) return false; + if (baudrate == 0) + { + debug("Invalid baudrate"); + return false; + } + for (uint8_t i = 0; i < SOFTUART_MAX_UARTS; i++) + if (uarts[i].baudrate && i != uart_no + && (uarts[i].rx_pin == rx_pin || uarts[i].tx_pin == tx_pin || uarts[i].rx_pin == tx_pin || uarts[i].tx_pin == rx_pin)) + { + debug("Cannot share pins between uarts"); + return false; + } + + softuart_close(uart_no); + + softuart_t *uart = uarts + uart_no; + + uart->baudrate = baudrate; + uart->rx_pin = rx_pin; + uart->tx_pin = tx_pin; + + // Calculate bit_time + uart->bit_time = (1000000 / baudrate); + if (((100000000 / baudrate) - (100 * uart->bit_time)) > 50) uart->bit_time++; + + // Setup Rx + gpio_enable(rx_pin, GPIO_INPUT); + gpio_set_pullup(rx_pin, true, false); + + // Setup Tx + gpio_enable(tx_pin, GPIO_OUTPUT); + gpio_set_pullup(tx_pin, true, false); + gpio_write(tx_pin, 1); + + // Setup the interrupt handler to get the start bit + gpio_set_interrupt(rx_pin, GPIO_INTTYPE_EDGE_NEG, handle_rx); + + sdk_os_delay_us(1000); // TODO: not sure if it really needed + + return true; +} + +bool softuart_close(uint8_t uart_no) +{ + if (!check_uart_no(uart_no)) return false; + softuart_t *uart = uarts + uart_no; + + if (!uart->baudrate) return true; + + // Remove interrupt + gpio_set_interrupt(uart->rx_pin, GPIO_INTTYPE_NONE, NULL); + // Mark as unused + uart->baudrate = 0; + + return true; +} + +bool softuart_put(uint8_t uart_no, char c) +{ + if (!check_uart_no(uart_no)) return false; + if (!check_uart_enabled(uart_no)) return false; + softuart_t *uart = uarts + uart_no; + + uint32_t start_time = 0x7FFFFFFF & sdk_system_get_time(); + gpio_write(uart->tx_pin, 0); + + for (uint8_t i = 0; i <= 8; i++) + { + while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * (i + 1)))) + { + if ((0x7FFFFFFF & sdk_system_get_time()) < start_time) + break; + } + gpio_write(uart->tx_pin, c & (1 << i)); + } + + while ((0x7FFFFFFF & sdk_system_get_time()) < (start_time + (uart->bit_time * 9))) + { + if ((0x7FFFFFFF & sdk_system_get_time()) < start_time) + break; + } + gpio_write(uart->tx_pin, 1); + sdk_os_delay_us(uart->bit_time * 6); + + return true; +} + +bool softuart_puts(uint8_t uart_no, const char *s) +{ + while (*s) + { + if (!softuart_put(uart_no, *s++)) + return false; + } + + return true; +} + +bool softuart_available(uint8_t uart_no) +{ + if (!check_uart_no(uart_no)) return false; + if (!check_uart_enabled(uart_no)) return false; + softuart_t *uart = uarts + uart_no; + + return (uart->buffer.receive_buffer_tail + SOFTUART_MAX_RX_BUFF - uart->buffer.receive_buffer_head) % SOFTUART_MAX_RX_BUFF; +} + +uint8_t softuart_read(uint8_t uart_no) +{ + if (!check_uart_no(uart_no)) return 0; + if (!check_uart_enabled(uart_no)) return 0; + softuart_t *uart = uarts + uart_no; + + // Empty buffer? + if (uart->buffer.receive_buffer_head == uart->buffer.receive_buffer_tail) return 0; + + // Read from "head" + uint8_t d = uart->buffer.receive_buffer[uart->buffer.receive_buffer_head]; // grab next byte + uart->buffer.receive_buffer_head = (uart->buffer.receive_buffer_head + 1) % SOFTUART_MAX_RX_BUFF; + return d; +} + diff --git a/extras/softuart/softuart.h b/extras/softuart/softuart.h new file mode 100644 index 0000000..e5fa8f6 --- /dev/null +++ b/extras/softuart/softuart.h @@ -0,0 +1,93 @@ +/* + * Softuart for esp-open-rtos + * + * Copyright (C) 2017 Ruslan V. Uss + * Copyright (C) 2016 Bernhard Guillon + * + * This code is based on Softuart from here [1] and reworked to + * fit into esp-open-rtos. For now only the RX part is ported. + * Also the configuration of the pin is for now hardcoded. + * + * it fits my needs to read the GY-GPS6MV2 module with 9600 8n1 + * + * Original Copyright: + * Copyright (c) 2015 plieningerweb + * + * MIT Licensed as described in the file LICENSE + * + * 1 https://github.com/plieningerweb/esp8266-software-uart + */ +#ifndef SOFTUART_H_ +#define SOFTUART_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifndef SOFTUART_MAX_UARTS + #define SOFTUART_MAX_UARTS 2 +#endif + +#ifndef SOFTUART_MAX_RX_BUFF + #define SOFTUART_MAX_RX_BUFF 64 //!< Must be power of two: 2, 4, 8, 16 etc. +#endif + +/** + * Initialize software uart and setup interrupt handler + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @param baudrate Baudrate, e.g. 9600, 19200, etc + * @param rx_pin GPIO pin number for RX + * @param tx_pin GPIO pin number for TX + * @return true if no errors occured otherwise false + */ +bool softuart_open(uint8_t uart_no, uint32_t baudrate, uint8_t rx_pin, uint8_t tx_pin); + +/** + * Deinitialize software uart + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @return true if no errors occured otherwise false + */ +bool softuart_close(uint8_t uart_no); + +/** + * Put char to software uart + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @param c Char + * @return true if no errors occured otherwise false + */ +bool softuart_put(uint8_t uart_no, char c); + +/** + * Put string to software uart + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @param s Null-terminated string + * @return true if no errors occured otherwise false + */ +bool softuart_puts(uint8_t uart_no, const char *s); + +/** + * Check if data is available + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @return true if data is available otherwise false + */ +bool softuart_available(uint8_t uart_no); + +/** + * Read current byte from internal buffer if available. + * + * NOTE: This call is non blocking. + * NOTE: You have to check softuart_available() first. + * @param uart_no Software uart index, 0..SOFTUART_MAX_UARTS + * @return current byte if available otherwise 0 + */ +uint8_t softuart_read(uint8_t uart_no); + +#ifdef __cplusplus +} +#endif + +#endif /* SOFTUART_H_ */ diff --git a/extras/spiffs/esp_spiffs.c b/extras/spiffs/esp_spiffs.c index 3d81218..58f1d33 100644 --- a/extras/spiffs/esp_spiffs.c +++ b/extras/spiffs/esp_spiffs.c @@ -7,11 +7,10 @@ */ #include "esp_spiffs.h" #include "spiffs.h" -#include +#include #include #include #include -#include "esp_spiffs_flash.h" spiffs fs; @@ -34,7 +33,7 @@ static fs_buf_t cache_buf = {0}; static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst) { - if (esp_spiffs_flash_read(addr, dst, size) == ESP_SPIFFS_FLASH_ERROR) { + if (!spiflash_read(addr, dst, size)) { return SPIFFS_ERR_INTERNAL; } @@ -43,7 +42,7 @@ static s32_t esp_spiffs_read(u32_t addr, u32_t size, u8_t *dst) static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) { - if (esp_spiffs_flash_write(addr, src, size) == ESP_SPIFFS_FLASH_ERROR) { + if (!spiflash_write(addr, src, size)) { return SPIFFS_ERR_INTERNAL; } @@ -52,11 +51,10 @@ static s32_t esp_spiffs_write(u32_t addr, u32_t size, u8_t *src) static s32_t esp_spiffs_erase(u32_t addr, u32_t size) { - uint32_t sectors = size / SPI_FLASH_SEC_SIZE; + uint32_t sectors = size / SPI_FLASH_SECTOR_SIZE; for (uint32_t i = 0; i < sectors; i++) { - if (esp_spiffs_flash_erase_sector(addr + (SPI_FLASH_SEC_SIZE * i)) - == ESP_SPIFFS_FLASH_ERROR) { + if (!spiflash_erase_sector(addr + (SPI_FLASH_SECTOR_SIZE * i))) { return SPIFFS_ERR_INTERNAL; } } diff --git a/extras/spiffs/unaligned_memcpy.S b/extras/spiffs/unaligned_memcpy.S deleted file mode 100644 index b96c92c..0000000 --- a/extras/spiffs/unaligned_memcpy.S +++ /dev/null @@ -1,112 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2016 sheinz (https://github.com/sheinz) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - - .text - .section .iram1.text, "x" - .literal_position - -/** - * Copy unaligned data to 4-byte aligned buffer. - */ - .align 4 - .global memcpy_unaligned_src - .type memcpy_unaligned_src, @function -memcpy_unaligned_src: -/* a2: dst, a3: src, a4: size */ - ssa8l a3 - srli a3, a3, 2 - slli a3, a3, 2 - beqz a4, u_src_end - l32i a6, a3, 0 -u_src_loop: - l32i a7, a3, 4 - src a8, a7, a6 - memw - s32i a8, a2, 0 - mov a6, a7 - addi a3, a3, 4 - addi a2, a2, 4 - addi a4, a4, -1 - bnez a4, u_src_loop -u_src_end: - movi a2, 0 - ret.n - - -/** - * Copy data from 4-byte aligned source to unaligned destination buffer. - */ - .align 4 - .global memcpy_unaligned_dst - .type memcpy_unaligned_dst, @function -memcpy_unaligned_dst: -/* a2: dst, a3: src, a4: size */ - beqz.n a4, u_dst_end - extui a5, a4, 0, 2 - beqz.n a5, aligned_dst_loop -u_dst_loop: - /* Load data word */ - memw - l32i.n a5, a3, 0 - - /* Save byte number 0 */ - s8i a5, a2, 0 - addi.n a4, a4, -1 - beqz a4, u_dst_end - addi.n a2, a2, 1 - - /* Shift and save byte number 1 */ - srli a5, a5, 8 - s8i a5, a2, 0 - addi.n a4, a4, -1 - beqz a4, u_dst_end - addi.n a2, a2, 1 - - /* Shift and save byte number 2 */ - srli a5, a5, 8 - s8i a5, a2, 0 - addi.n a4, a4, -1 - beqz a4, u_dst_end - addi.n a2, a2, 1 - - /* Shift and save byte number 3 */ - srli a5, a5, 8 - s8i a5, a2, 0 - addi.n a4, a4, -1 - addi.n a2, a2, 1 - - /* Next word */ - addi.n a3, a3, 4 - bnez.n a4, u_dst_loop - ret.n -aligned_dst_loop: - memw - l32i a5, a3, 0 - s32i a5, a2, 0 - addi.n a3, a3, 4 - addi.n a2, a2, 4 - addi.n a4, a4, -4 - bnez.n a4, aligned_dst_loop -u_dst_end: ret.n - diff --git a/extras/ssd1306/ssd1306.c b/extras/ssd1306/ssd1306.c index c4f43a9..372e867 100644 --- a/extras/ssd1306/ssd1306.c +++ b/extras/ssd1306/ssd1306.c @@ -11,9 +11,6 @@ */ #include "ssd1306.h" #include -#if (SSD1306_I2C_SUPPORT) - #include -#endif #if (SSD1306_SPI4_SUPPORT) || (SSD1306_SPI3_SUPPORT) #include #endif @@ -88,10 +85,18 @@ #define abs(x) ((x)<0 ? -(x) : (x)) #define swap(x, y) do { typeof(x) temp##x##y = x; x = y; y = temp##x##y; } while (0) + +#if (SSD1306_I2C_SUPPORT) +static int inline i2c_send(const ssd1306_t *dev, uint8_t reg, uint8_t* data, uint8_t len) +{ + return i2c_slave_write(dev->i2c_dev.bus, dev->i2c_dev.addr , ®, data, len); +} +#endif + /* Issue a command to SSD1306 device * I2C proto format: * |S|Slave Address|W|ACK|0x00|Command|Ack|P| - * + * * in case of two-bytes command here will be Data byte * right after the command byte. */ @@ -101,23 +106,7 @@ int ssd1306_command(const ssd1306_t *dev, uint8_t cmd) switch (dev->protocol) { #if (SSD1306_I2C_SUPPORT) case SSD1306_PROTO_I2C: - i2c_start(); - if (!i2c_write(dev->addr << 1)) { - debug("Error while xmitting I2C slave address\n"); - i2c_stop(); - return -EIO; - } - if (!i2c_write(0x00)) { - debug("Error while xmitting transmission type\n"); - i2c_stop(); - return -EIO; - } - if (!i2c_write(cmd)) { - debug("Error while xmitting command: 0x%02X\n", cmd); - i2c_stop(); - return -EIO; - } - i2c_stop(); + return i2c_send(dev, 0x00, &cmd, 1); break; #endif #if (SSD1306_SPI4_SUPPORT) @@ -247,7 +236,9 @@ int ssd1306_load_frame_buffer(const ssd1306_t *dev, uint8_t buf[]) { uint16_t i; uint8_t j; - +#if (SSD1306_I2C_SUPPORT) + uint8_t tab[16] = { 0 } ; +#endif size_t len = dev->width * dev->height / 8; if(dev->screen == SSD1306_SCREEN) { @@ -258,31 +249,11 @@ int ssd1306_load_frame_buffer(const ssd1306_t *dev, uint8_t buf[]) switch (dev->protocol) { #if (SSD1306_I2C_SUPPORT) case SSD1306_PROTO_I2C: - for (i = 0; i < len; i++) { + for (i = 0; i < len; i++) + { if(dev->screen == SH1106_SCREEN && i%dev->width == 0) sh1106_go_coordinate(dev,0,i/dev->width); - i2c_start(); - if (!i2c_write(dev->addr << 1)) { - debug("Error while xmitting I2C slave address\n"); - i2c_stop(); - return -EIO; - } - if (!i2c_write(0x40)) { - debug("Error while xmitting transmission type\n"); - i2c_stop(); - return -EIO; - } - - for (j = 0; j < 16; j++) { - if (!i2c_write(buf ? buf[i] : 0)) { - debug("Error while writing to GDDRAM\n"); - i2c_stop(); - return -EIO; - } - i++; - } - i--; - i2c_stop(); - taskYIELD(); + i2c_send(dev, 0x40, buf ? &buf[i] : tab, 16); + i+=15 ; } break; #endif @@ -319,9 +290,19 @@ int ssd1306_load_frame_buffer(const ssd1306_t *dev, uint8_t buf[]) { spi_set_command(SPI_BUS,1,1); // data mode if (buf) - spi_transfer(SPI_BUS, buf, NULL, len, SPI_8BIT); + { + for (i = 0; i < len; i++) + { + spi_transfer(SPI_BUS, &buf[i], NULL, 1, SPI_8BIT); + } + } else - spi_repeat_send_8(SPI_BUS,0,len); + { + for (i = 0; i < len; i++) + { + spi_transfer_8(SPI_BUS, 0); + } + } } else { diff --git a/extras/ssd1306/ssd1306.h b/extras/ssd1306/ssd1306.h index 9f620d1..639517b 100644 --- a/extras/ssd1306/ssd1306.h +++ b/extras/ssd1306/ssd1306.h @@ -19,6 +19,7 @@ // shifted #if (SSD1306_I2C_SUPPORT) + #include #define SSD1306_I2C_ADDR_0 (0x3C) #define SSD1306_I2C_ADDR_1 (0x3D) #endif @@ -67,7 +68,7 @@ typedef struct ssd1306_screen_t screen ; union { #if (SSD1306_I2C_SUPPORT) - uint8_t addr ; //!< I2C address, used by SSD1306_PROTO_I2C + i2c_dev_t i2c_dev; //!< I2C devuce descriptor, used by SSD1306_PROTO_I2C #endif uint8_t cs_pin ; //!< Chip Select GPIO pin, used by SSD1306_PROTO_SPI3, SSD1306_PROTO_SPI4 } ; @@ -192,14 +193,6 @@ int ssd1306_set_display_offset(const ssd1306_t *dev, uint8_t offset); */ int sh1106_set_charge_pump_voltage(const ssd1306_t *dev, sh1106_voltage_t select); -/** - * Select charge pump voltage. See value in datasheet. - * @param dev Pointer to device descriptor - * @param select Select charge pump voltage value - * @return Non-zero if error occured - */ -int sh1106_set_charge_pump_voltage(const ssd1306_t *dev, sh1106_voltage_t select); - /** * Enable or disable the charge pump. See application note in datasheet. * @param dev Pointer to device descriptor diff --git a/extras/stdin_uart_interrupt/stdin_uart_interrupt.c b/extras/stdin_uart_interrupt/stdin_uart_interrupt.c index 3319588..194fdda 100644 --- a/extras/stdin_uart_interrupt/stdin_uart_interrupt.c +++ b/extras/stdin_uart_interrupt/stdin_uart_interrupt.c @@ -44,7 +44,7 @@ static SemaphoreHandle_t uart0_sem = NULL; static bool inited = false; 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 if (!UART(UART0).INT_STATUS & UART_INT_STATUS_RXFIFO_FULL) { @@ -97,7 +97,7 @@ static void uart0_rx_init(void) int trig_lvl = 1; 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); // reset the rx fifo diff --git a/extras/tsl2561/tsl2561.c b/extras/tsl2561/tsl2561.c index 36c52e9..cc89021 100644 --- a/extras/tsl2561/tsl2561.c +++ b/extras/tsl2561/tsl2561.c @@ -6,7 +6,6 @@ #include #include "FreeRTOS.h" -#include "i2c/i2c.h" #include "task.h" #include "tsl2561.h" @@ -96,32 +95,32 @@ #define B8C 0x0000 // 0.000 * 2^LUX_SCALE #define M8C 0x0000 // 0.000 * 2^LUX_SCALE -static bool write_register(uint8_t i2c_addr, uint8_t reg, uint8_t value) +static int write_register(i2c_dev_t* i2c_dev, uint8_t reg, uint8_t value) { - uint8_t data[2]; - data[0] = TSL2561_REG_COMMAND | reg; - data[1] = value; - return i2c_slave_write(i2c_addr, data, 2); + reg = TSL2561_REG_COMMAND | reg; + return i2c_slave_write(i2c_dev->bus, i2c_dev->addr, ®, &value, 1); } -static uint8_t read_register(uint8_t i2c_addr, uint8_t reg) +static uint8_t read_register(i2c_dev_t* i2c_dev, uint8_t reg) { uint8_t data[1]; + reg = TSL2561_REG_COMMAND | reg; - if (!i2c_slave_read(i2c_addr, TSL2561_REG_COMMAND | reg, data, 1)) + if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, ®, data, 1)) { - printf("Error in tsl261 read_register\n"); + printf("Error in tsl2561 read_register\n"); } return data[0]; } -static uint16_t read_register_16(uint8_t i2c_addr, uint8_t low_register_addr) +static uint16_t read_register_16(i2c_dev_t* i2c_dev, uint8_t low_register_addr) { uint16_t value = 0; uint8_t data[2]; + low_register_addr = TSL2561_REG_COMMAND | TSL2561_READ_WORD | low_register_addr; - if (!i2c_slave_read(i2c_addr, TSL2561_REG_COMMAND | TSL2561_READ_WORD | low_register_addr, data, 2)) + if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, &low_register_addr, data, 2)) { printf("Error with i2c_slave_read in read_register_16\n"); } @@ -131,24 +130,24 @@ static uint16_t read_register_16(uint8_t i2c_addr, uint8_t low_register_addr) return value; } -static bool enable(uint8_t i2c_addr) +static int enable(i2c_dev_t* i2c_dev) { - return write_register(i2c_addr, TSL2561_REG_CONTROL, TSL2561_ON); + return write_register(i2c_dev, TSL2561_REG_CONTROL, TSL2561_ON); } -static bool disable(uint8_t i2c_addr) +static int disable(i2c_dev_t* i2c_dev) { - return write_register(i2c_addr, TSL2561_REG_CONTROL, TSL2561_OFF); + return write_register(i2c_dev, TSL2561_REG_CONTROL, TSL2561_OFF); } void tsl2561_init(tsl2561_t *device) { - if (!enable(device->i2c_addr)) + if (enable(&device->i2c_dev)) { printf("Error initializing tsl2561\n"); } - uint8_t control_reg = (read_register(device->i2c_addr, TSL2561_REG_CONTROL) & TSL2561_ON); + uint8_t control_reg = (read_register(&device->i2c_dev, TSL2561_REG_CONTROL) & TSL2561_ON); if (control_reg != TSL2561_ON) { @@ -156,39 +155,39 @@ void tsl2561_init(tsl2561_t *device) } // Fetch the package type - uint8_t part_reg = read_register(device->i2c_addr, TSL2561_REG_PART_ID); + uint8_t part_reg = read_register(&device->i2c_dev, TSL2561_REG_PART_ID); uint8_t package = part_reg >> 6; device->package_type = package; // Fetch the gain and integration time - uint8_t timing_register = read_register(device->i2c_addr, TSL2561_REG_TIMING); + uint8_t timing_register = read_register(&device->i2c_dev, TSL2561_REG_TIMING); device->gain = timing_register & 0x10; device->integration_time = timing_register & 0x03; - disable(device->i2c_addr); + disable(&device->i2c_dev); } void tsl2561_set_integration_time(tsl2561_t *device, tsl2561_integration_time_t integration_time_id) { - enable(device->i2c_addr); - write_register(device->i2c_addr, TSL2561_REG_TIMING, integration_time_id | device->gain); - disable(device->i2c_addr); + enable(&device->i2c_dev); + write_register(&device->i2c_dev, TSL2561_REG_TIMING, integration_time_id | device->gain); + disable(&device->i2c_dev); device->integration_time = integration_time_id; } void tsl2561_set_gain(tsl2561_t *device, tsl2561_gain_t gain) { - enable(device->i2c_addr); - write_register(device->i2c_addr, TSL2561_REG_TIMING, gain | device->integration_time); - disable(device->i2c_addr); + enable(&device->i2c_dev); + write_register(&device->i2c_dev, TSL2561_REG_TIMING, gain | device->integration_time); + disable(&device->i2c_dev); device->gain = gain; } static void get_channel_data(tsl2561_t *device, uint16_t *channel0, uint16_t *channel1) { - enable(device->i2c_addr); + enable(&device->i2c_dev); // Since we just enabled the chip, we need to sleep // for the chip's integration time so it can gather a reading @@ -205,10 +204,10 @@ static void get_channel_data(tsl2561_t *device, uint16_t *channel0, uint16_t *ch break; } - *channel0 = read_register_16(device->i2c_addr, TSL2561_REG_CHANNEL_0_LOW); - *channel1 = read_register_16(device->i2c_addr, TSL2561_REG_CHANNEL_1_LOW); + *channel0 = read_register_16(&device->i2c_dev, TSL2561_REG_CHANNEL_0_LOW); + *channel1 = read_register_16(&device->i2c_dev, TSL2561_REG_CHANNEL_1_LOW); - disable(device->i2c_addr); + disable(&device->i2c_dev); } bool tsl2561_read_lux(tsl2561_t *device, uint32_t *lux) diff --git a/extras/tsl2561/tsl2561.h b/extras/tsl2561/tsl2561.h index ad5109f..9f880b3 100644 --- a/extras/tsl2561/tsl2561.h +++ b/extras/tsl2561/tsl2561.h @@ -9,6 +9,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -38,7 +39,7 @@ typedef enum } tsl2561_gain_t; typedef struct { - tsl2561_i2c_addr_t i2c_addr; + i2c_dev_t i2c_dev; uint8_t integration_time; uint8_t gain; uint8_t package_type; diff --git a/extras/tsl4531/component.mk b/extras/tsl4531/component.mk new file mode 100644 index 0000000..8752823 --- /dev/null +++ b/extras/tsl4531/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/tsl4531 + +# Include the TSL4531 driver as "tsl4531/tsl4531.h" +INC_DIRS += $(tsl4531_ROOT).. + +# args for passing into compile rule generation +tsl4531_SRC_DIR = $(tsl4531_ROOT) + +$(eval $(call component_compile_rules,tsl4531)) diff --git a/extras/tsl4531/tsl4531.c b/extras/tsl4531/tsl4531.c new file mode 100644 index 0000000..a15a0ee --- /dev/null +++ b/extras/tsl4531/tsl4531.c @@ -0,0 +1,165 @@ +/* + * Part of esp-open-rtos + * Copyright (C) 2017 Brian Schwind (https://github.com/bschwind) + * BSD Licensed as described in the file LICENSE + */ + +#include +#include "FreeRTOS.h" +#include "task.h" +#include "tsl4531.h" + +// Registers +#define TSL4531_REG_COMMAND 0x80 +#define TSL4531_REG_CONTROL 0x00 +#define TSL4531_REG_CONFIG 0x01 +#define TSL4531_REG_DATA_LOW 0x04 +#define TSL4531_REG_DATA_HIGH 0x05 +#define TSL4531_REG_DEVICE_ID 0x0A + +// TSL4531 Misc Values +#define TSL4531_ON 0x03 +#define TSL4531_OFF 0x00 + +// Integration times in milliseconds +#define TSL4531_INTEGRATION_TIME_100MS 120 +#define TSL4531_INTEGRATION_TIME_200MS 240 +#define TSL4531_INTEGRATION_TIME_400MS 480 // Default + +static int write_register(i2c_dev_t* i2c_dev, uint8_t reg, uint8_t value) +{ + reg = TSL4531_REG_COMMAND | reg; + return i2c_slave_write(i2c_dev->bus, i2c_dev->addr, ®, &value, 1); +} + +static uint8_t read_register(i2c_dev_t* i2c_dev, uint8_t reg) +{ + uint8_t data[1]; + reg = TSL4531_REG_COMMAND | reg; + + if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, ®, data, 1)) + { + printf("Error in tsl4531 read_register\n"); + } + + return data[0]; +} + +static uint16_t read_register_16(i2c_dev_t* i2c_dev, uint8_t low_register_addr) +{ + uint16_t value = 0; + uint8_t data[2]; + low_register_addr = TSL4531_REG_COMMAND | low_register_addr; + + if (i2c_slave_read(i2c_dev->bus, i2c_dev->addr, &low_register_addr, data, 2)) + { + printf("Error with i2c_slave_read in read_register_16\n"); + } + + value = ((uint16_t)data[1] << 8) | (data[0]); + + return value; +} + +static int enable(tsl4531_t *device) +{ + return write_register(&device->i2c_dev, TSL4531_REG_CONTROL, TSL4531_ON); +} + +static int disable(tsl4531_t *device) +{ + return write_register(&device->i2c_dev, TSL4531_REG_CONTROL, TSL4531_OFF); +} + +void tsl4531_init(tsl4531_t *device) +{ + if (enable(device)) + { + printf("Error initializing tsl4531, the enable write failed\n"); + } + + uint8_t control_reg = read_register(&device->i2c_dev, TSL4531_REG_CONTROL); + + if (control_reg != TSL4531_ON) { + printf("Error initializing tsl4531, control register wasn't set to ON\n"); + } + + uint8_t idRegister = read_register(&device->i2c_dev, TSL4531_REG_DEVICE_ID); + uint8_t id = (idRegister & 0xF0) >> 4; + + if (id == TSL4531_PART_TSL45317) { + device->part_id = TSL4531_PART_TSL45317; + } else if (id == TSL4531_PART_TSL45313) { + device->part_id = TSL4531_PART_TSL45313; + } else if (id == TSL4531_PART_TSL45315) { + device->part_id = TSL4531_PART_TSL45315; + } else if (id == TSL4531_PART_TSL45311) { + device->part_id = TSL4531_PART_TSL45311; + } else { + printf("Unknown part id for TSL4531 sensor: %u\n", id); + } + + disable(device); +} + +void tsl4531_set_integration_time(tsl4531_t *device, tsl4531_integration_time_t integration_time_id) +{ + uint8_t power_save_bit = device->skip_power_save ? 0x08 : 0x00; + uint8_t integration_time_bits = 0x03 & integration_time_id; + uint8_t new_config_reg = power_save_bit | integration_time_bits; + + enable(device); + write_register(&device->i2c_dev, TSL4531_REG_CONFIG, new_config_reg); + disable(device); + + device->integration_time_id = integration_time_id; +} + +void tsl4531_set_power_save_skip(tsl4531_t *device, bool skip_power_save) +{ + uint8_t power_save_bit = skip_power_save ? 0x08 : 0x00; + uint8_t integration_time_bits = 0x03 & device->integration_time_id; + uint8_t new_config_reg = power_save_bit | integration_time_bits; + + enable(device); + write_register(&device->i2c_dev, TSL4531_REG_CONFIG, new_config_reg); + disable(device); + + device->skip_power_save = skip_power_save; +} + +bool tsl4531_read_lux(tsl4531_t *device, uint16_t *lux) +{ + bool success = true; + uint16_t multiplier = 1; + + enable(device); + + switch (device->integration_time_id) + { + case TSL4531_INTEGRATION_100MS: + multiplier = 4; + vTaskDelay(TSL4531_INTEGRATION_TIME_100MS / portTICK_PERIOD_MS); + break; + case TSL4531_INTEGRATION_200MS: + multiplier = 2; + vTaskDelay(TSL4531_INTEGRATION_TIME_200MS / portTICK_PERIOD_MS); + break; + case TSL4531_INTEGRATION_400MS: + multiplier = 1; + vTaskDelay(TSL4531_INTEGRATION_TIME_400MS / portTICK_PERIOD_MS); + break; + default: + multiplier = 1; + vTaskDelay(TSL4531_INTEGRATION_TIME_400MS / portTICK_PERIOD_MS); + break; + } + + uint16_t lux_data = read_register_16(&device->i2c_dev, TSL4531_REG_DATA_LOW); + + disable(device); + + *lux = multiplier * lux_data; + + return success; +} diff --git a/extras/tsl4531/tsl4531.h b/extras/tsl4531/tsl4531.h new file mode 100644 index 0000000..d4ab7ec --- /dev/null +++ b/extras/tsl4531/tsl4531.h @@ -0,0 +1,57 @@ +/* + * Part of esp-open-rtos + * Copyright (C) 2017 Brian Schwind (https://github.com/bschwind) + * BSD Licensed as described in the file LICENSE + */ + +#ifndef __TSL4531_H__ +#define __TSL4531_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// I2C Addresses +typedef enum +{ + TSL4531_I2C_ADDR = 0x29 +} tsl4531_i2c_addr_t; + +// Integration time IDs +typedef enum +{ + TSL4531_INTEGRATION_100MS = 0x02, + TSL4531_INTEGRATION_200MS = 0x01, + TSL4531_INTEGRATION_400MS = 0x00 // Default +} tsl4531_integration_time_t; + +// Part IDs +typedef enum +{ + TSL4531_PART_TSL45317 = 0x08, + TSL4531_PART_TSL45313 = 0x09, + TSL4531_PART_TSL45315 = 0x0A, + TSL4531_PART_TSL45311 = 0x0B +} tsl4531_part_id_t; + +typedef struct { + i2c_dev_t i2c_dev; + uint8_t integration_time_id; + bool skip_power_save; + tsl4531_part_id_t part_id; +} tsl4531_t; + +void tsl4531_init(tsl4531_t *device); +void tsl4531_set_integration_time(tsl4531_t *device, tsl4531_integration_time_t integration_time_id); +void tsl4531_set_power_save_skip(tsl4531_t *device, bool skip_power_save); +bool tsl4531_read_lux(tsl4531_t *device, uint16_t *lux); + +#ifdef __cplusplus +} +#endif + +#endif // __TSL4531_H__ diff --git a/extras/ultrasonic/ultrasonic.c b/extras/ultrasonic/ultrasonic.c index f6a21f6..21ae493 100644 --- a/extras/ultrasonic/ultrasonic.c +++ b/extras/ultrasonic/ultrasonic.c @@ -15,6 +15,8 @@ #define PING_TIMEOUT 6000 #define ROUNDTRIP 58 +#define timeout_expired(start, len) ((uint32_t)(sdk_system_get_time() - (start)) >= (len)) + void ultrasoinc_init(const ultrasonic_sensor_t *dev) { gpio_enable(dev->trigger_pin, GPIO_OUTPUT); @@ -36,21 +38,21 @@ int32_t ultrasoinc_measure_cm(const ultrasonic_sensor_t *dev, uint32_t max_dista return ULTRASONIC_ERROR_PING; // Wait for echo - uint32_t timeout = sdk_system_get_time() + PING_TIMEOUT; + uint32_t start = sdk_system_get_time(); while (!gpio_read(dev->echo_pin)) { - if (sdk_system_get_time() >= timeout) + if (timeout_expired(start, PING_TIMEOUT)) return ULTRASONIC_ERROR_PING_TIMEOUT; } // got echo, measuring uint32_t echo_start = sdk_system_get_time(); uint32_t time = echo_start; - timeout = echo_start + max_distance * ROUNDTRIP; + uint32_t meas_timeout = echo_start + max_distance * ROUNDTRIP; while (gpio_read(dev->echo_pin)) { time = sdk_system_get_time(); - if (time >= timeout) + if (timeout_expired(echo_start, meas_timeout)) return ULTRASONIC_ERROR_ECHO_TIMEOUT; } diff --git a/extras/wificfg/component.mk b/extras/wificfg/component.mk new file mode 100644 index 0000000..5412c52 --- /dev/null +++ b/extras/wificfg/component.mk @@ -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)) diff --git a/extras/wificfg/content/challenge.html b/extras/wificfg/content/challenge.html new file mode 100644 index 0000000..568ead2 --- /dev/null +++ b/extras/wificfg/content/challenge.html @@ -0,0 +1,30 @@ +"" +"" +"" +"" +"", +"" +"" +"" +"" +"" +"
" +"
" +"Unlock the configuration interface" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"" diff --git a/extras/wificfg/content/favicon.ico b/extras/wificfg/content/favicon.ico new file mode 100644 index 0000000..93f7af2 --- /dev/null +++ b/extras/wificfg/content/favicon.ico @@ -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", +"" +"" +"" +"" +"" diff --git a/extras/wificfg/content/script.js b/extras/wificfg/content/script.js new file mode 100644 index 0000000..68064c5 --- /dev/null +++ b/extras/wificfg/content/script.js @@ -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\"; } }" diff --git a/extras/wificfg/content/style.css b/extras/wificfg/content/style.css new file mode 100644 index 0000000..9155940 --- /dev/null +++ b/extras/wificfg/content/style.css @@ -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}" diff --git a/extras/wificfg/content/tasks.html b/extras/wificfg/content/tasks.html new file mode 100644 index 0000000..d084ea7 --- /dev/null +++ b/extras/wificfg/content/tasks.html @@ -0,0 +1,18 @@ +"" +"" +"" +"" +"", +"" +"" +"" +"" +"", +"" diff --git a/extras/wificfg/content/wificfg/ap.html b/extras/wificfg/content/wificfg/ap.html new file mode 100644 index 0000000..8dbb730 --- /dev/null +++ b/extras/wificfg/content/wificfg/ap.html @@ -0,0 +1,90 @@ +"" +"" +"" +"" +"", +"" +"" +"" +"" +"" +"
" +"
" +"WiFi Access Point configuration" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
 
" +"
" +"" +"
" +"" diff --git a/extras/wificfg/content/wificfg/index.html b/extras/wificfg/content/wificfg/index.html new file mode 100644 index 0000000..cb81712 --- /dev/null +++ b/extras/wificfg/content/wificfg/index.html @@ -0,0 +1,52 @@ +"" +"" +"" +"" +"", +"" +"" +"" +"" +"" +"

WiFi Status

" +"
", +"
" +"
" +"
" +"
" +"Lock the configuration interface" +"

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.

" +"
" +"
" +"
" +"
" +"" +"
" +"
" +"
" +"
" +"
" +"Restart device" +"

A restart is necessary for some changes to take effect.

" +"
" +"
" +"
" +"
" +"Erase configuration" +"

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." +"

" +"
" +"
" +"
", +"" diff --git a/extras/wificfg/content/wificfg/sta.html b/extras/wificfg/content/wificfg/sta.html new file mode 100644 index 0000000..65bfe9d --- /dev/null +++ b/extras/wificfg/content/wificfg/sta.html @@ -0,0 +1,68 @@ +"" +"" +"" +"" +"", +"" +"" +"" +"" +"" +"
" +"
" +"WiFi Station configuration" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
" +"
 
" +"
" +"" +"
" +"" diff --git a/extras/wificfg/wificfg.c b/extras/wificfg/wificfg.c new file mode 100644 index 0000000..708af29 --- /dev/null +++ b/extras/wificfg/wificfg.c @@ -0,0 +1,2022 @@ +/* + * 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. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "lwip/err.h" +#include "lwip/sockets.h" +#include "lwip/sys.h" +#include "lwip/netdb.h" +#include "lwip/dns.h" + +#include "wificfg.h" +#include "sysparam.h" + +char *wificfg_default_ssid = "EOR_%02X%02X%02X"; +char *wificfg_default_password = "esp-open-rtos"; +char *wificfg_default_hostname = "eor-%02x%02x%02x"; + +/* The http task stack allocates a single buffer to do much of it's work. */ +#define HTTP_BUFFER_SIZE 54 + +/* + * Read a line terminated by "\r\n" or "\n" to be robust. Used to read the http + * status line and headers. On success returns the number of characters read, + * which might be more that the available buffer size 'len'. Excess characters + * in a line are discarded as a protection against excessively long lines. On + * failure -1 is returned. The character case is lowered to give a canonical + * case for easier comparision. The buffer is null terminated on success, even + * if truncated. + */ +static int read_crlf_line(int s, char *buf, size_t len) +{ + size_t num = 0; + + do { + char c; + int r = read(s, &c, 1); + + /* Expecting a known terminator so fail on EOF. */ + if (r <= 0) + return -1; + + if (c == '\n') + break; + + /* Remove a trailing '\r', and many unexpected characters. */ + if (c < 0x20 || c > 0x7e) + continue; + + if (num < len) + buf[num] = tolower((unsigned char)c); + + num++; + } while(1); + + /* Null terminate. */ + buf[num >= len ? len - 1 : num] = 0; + + return num; +} + +int wificfg_form_name_value(int s, bool *valp, size_t *rem, char *buf, size_t len) +{ + size_t num = 0; + + do { + if (*rem == 0) + break; + + char c; + int r = read(s, &c, 1); + + /* Expecting a known number of characters so fail on EOF. */ + if (r <= 0) return -1; + + (*rem)--; + + if (valp && c == '=') { + *valp = true; + break; + } + + if (c == '&') { + if (valp) + *valp = false; + break; + } + + if (num < len) + buf[num] = c; + + num++; + } while(1); + + /* Null terminate. */ + buf[num >= len ? len - 1 : num] = 0; + + return num; +} + +void wificfg_form_url_decode(char *string) +{ + char *src = string; + char *src_end = string + strlen(string); + char *dst = string; + + while (src < src_end) { + char c = *src++; + if (c == '+') { + c = ' '; + } else if (c == '%' && src < src_end - 1) { + unsigned char c1 = src[0]; + unsigned char c2 = src[1]; + if (isxdigit(c1) && isxdigit(c2)) { + c1 = tolower(c1); + int d1 = (c1 >= 'a' && c1 <= 'z') ? c1 - 'a' + 10 : c1 - '0'; + c2 = tolower(c2); + int d2 = (c2 >= 'a' && c2 <= 'z') ? c2 - 'a' + 10 : c2 - '0'; + *dst++ = (d1 << 4) + d2; + src += 2; + continue; + } + } + *dst++ = c; + } + + *dst = 0; +} + +/* HTML escaping. */ +void wificfg_html_escape(char *string, char *buf, size_t len) +{ + size_t i; + size_t out = 0; + + for (i = 0, out = 0; out < len - 1; ) { + char c = string[i++]; + if (!c) + break; + + if (c == '&') { + if (out >= len - 5) + break; + buf[out] = '&'; + buf[out + 1] = 'a'; + buf[out + 2] = 'm'; + buf[out + 3] = 'p'; + buf[out + 4] = ';'; + out += 5; + continue; + } + if (c == '"') { + if (out >= len - 6) + break; + buf[out] = '&'; + buf[out + 1] = 'q'; + buf[out + 2] = 'u'; + buf[out + 3] = 'o'; + buf[out + 4] = 't'; + buf[out + 5] = ';'; + out += 6; + continue; + } + if (c == '<') { + if (out >= len - 4) + break; + buf[out] = '&'; + buf[out + 1] = 'l'; + buf[out + 2] = 't'; + buf[out + 3] = ';'; + out += 4; + continue; + } + if (c == '>') { + if (out >= len - 4) + break; + buf[out] = '&'; + buf[out + 1] = 'g'; + buf[out + 2] = 't'; + buf[out + 3] = ';'; + out += 4; + continue; + } + + buf[out++] = c; + } + + buf[out] = 0; +} + +/* Various keywords are interned as they are read. */ + +static const struct { + const char *str; + wificfg_method method; +} method_table[] = { + {"get", HTTP_METHOD_GET}, + {"post", HTTP_METHOD_POST}, + {"head", HTTP_METHOD_HEAD} +}; + +static wificfg_method intern_http_method(char *str) +{ + int i; + for (i = 0; i < sizeof(method_table) / sizeof(method_table[0]); i++) { + if (!strcmp(str, method_table[i].str)) + return method_table[i].method; + } + return HTTP_METHOD_OTHER; +} + +/* + * The web server recognizes only these header names. Other headers are ignored. + */ +typedef enum { + HTTP_HEADER_HOST, + HTTP_HEADER_CONTENT_LENGTH, + HTTP_HEADER_CONTENT_TYPE, + HTTP_HEADER_CONNECTION, + HTTP_HEADER_OTHER +} http_header; + +static const struct { + const char *str; + http_header name; +} http_header_table[] = { + {"host", HTTP_HEADER_HOST}, + {"content-length", HTTP_HEADER_CONTENT_LENGTH}, + {"content-type", HTTP_HEADER_CONTENT_TYPE}, + {"connection", HTTP_HEADER_CONNECTION} +}; + +static http_header intern_http_header(char *str) +{ + int i; + for (i = 0; i < sizeof(http_header_table) / sizeof(http_header_table[0]); i++) { + if (!strcmp(str, http_header_table[i].str)) + return http_header_table[i].name; + } + return HTTP_HEADER_OTHER; +} + + +static const struct { + const char *str; + wificfg_content_type type; +} content_type_table[] = { + {"application/x-www-form-urlencoded", HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED} +}; + +static wificfg_content_type intern_http_content_type(char *str) +{ + int i; + for (i = 0; i < sizeof(content_type_table) / sizeof(content_type_table[0]); i++) { + if (!strcmp(str, content_type_table[i].str)) + return content_type_table[i].type; + } + return HTTP_CONTENT_TYPE_OTHER; +} + +static char *skip_whitespace(char *string) +{ + while (isspace((unsigned char)*string)) string++; + return string; +} + +static char *skip_to_whitespace(char *string) +{ + do { + unsigned char c = *string; + if (!c || isspace(c)) + break; + string++; + } while (1); + + return string; +} + +int wificfg_write_string(int s, const char *str) +{ + int res = write(s, str, strlen(str)); + return res; +} + +int wificfg_write_string_chunk(int s, const char *str, char *buf, size_t len) +{ + size_t str_len = strlen(str); + + if (str_len == 0) { + /* Can not be encoded, would be EOF. */ + return 0; + } + + if (str_len + 6 < len) { + /* Can fit the chunk in the buffer. */ + memmove(buf + 4, str, str_len); + size_t start = 1; + if (str_len < 10) { + buf[1] = '0' + str_len; + } else if (str_len < 16) { + buf[1] = 'a' + str_len - 10; + } else { + uint32_t digit0 = str_len >> 4; + if (digit0 < 10) { + buf[0] = '0' + digit0; + } else { + buf[0] = 'a' + digit0 - 10; + } + uint32_t digit1 = str_len & 0xf; + if (digit1 < 10) { + buf[1] = '0' + digit1; + } else { + buf[1] = 'a' + digit1 - 10; + } + start = 0; + } + buf[2] = '\r'; + buf[3] = '\n'; + buf[4 + str_len] = '\r'; + buf[4 + str_len + 1] = '\n'; + return write(s, buf + start, 4 - start + str_len + 2); + } + + /* Else too big for the buffer. */ + char size_buf[8]; + size_t size_len = snprintf(size_buf, sizeof(size_buf), "%x\r\n", str_len); + int res = write(s, size_buf, size_len); + if (res != size_len) { + return res; + } + res = write(s, str, str_len); + if (res != str_len) { + return res; + } + return write(s, size_buf + size_len - 2, 2); +} + +int wificfg_write_chunk_end(int s) +{ + return wificfg_write_string(s, "0\r\n\r\n"); +} + +typedef enum { + FORM_NAME_CFG_ENABLE, + FORM_NAME_CFG_PASSWORD, + FORM_NAME_HOSTNAME, + FORM_NAME_STA_ENABLE, + FORM_NAME_STA_DISABLED_RESTARTS, + FORM_NAME_STA_SSID, + FORM_NAME_STA_PASSWORD, + FORM_NAME_STA_DHCP, + FORM_NAME_STA_IP_ADDR, + FORM_NAME_STA_NETMASK, + FORM_NAME_STA_GATEWAY, + FORM_NAME_AP_ENABLE, + FORM_NAME_AP_DISABLE_IF_STA, + FORM_NAME_AP_DISABLED_RESTARTS, + FORM_NAME_AP_SSID, + FORM_NAME_AP_PASSWORD, + FORM_NAME_AP_SSID_HIDDEN, + FORM_NAME_AP_CHANNEL, + FORM_NAME_AP_AUTHMODE, + FORM_NAME_AP_MAX_CONN, + FORM_NAME_AP_BEACON_INTERVAL, + FORM_NAME_AP_IP_ADDR, + FORM_NAME_AP_NETMASK, + FORM_NAME_AP_DHCP_LEASES, + FORM_NAME_AP_DNS, + FORM_NAME_DONE, + FORM_NAME_NONE +} form_name; + +static const struct { + const char *str; + form_name name; +} form_name_table[] = { + {"cfg_enable", FORM_NAME_CFG_ENABLE}, + {"cfg_password", FORM_NAME_CFG_PASSWORD}, + {"hostname", FORM_NAME_HOSTNAME}, + {"sta_enable", FORM_NAME_STA_ENABLE}, + {"sta_disabled_restarts", FORM_NAME_STA_DISABLED_RESTARTS}, + {"sta_ssid", FORM_NAME_STA_SSID}, + {"sta_dhcp", FORM_NAME_STA_DHCP}, + {"sta_password", FORM_NAME_STA_PASSWORD}, + {"sta_ip_addr", FORM_NAME_STA_IP_ADDR}, + {"sta_netmask", FORM_NAME_STA_NETMASK}, + {"sta_gateway", FORM_NAME_STA_GATEWAY}, + {"ap_enable", FORM_NAME_AP_ENABLE}, + {"ap_disable_if_sta", FORM_NAME_AP_DISABLE_IF_STA}, + {"ap_disabled_restarts", FORM_NAME_AP_DISABLED_RESTARTS}, + {"ap_ssid", FORM_NAME_AP_SSID}, + {"ap_password", FORM_NAME_AP_PASSWORD}, + {"ap_ssid_hidden", FORM_NAME_AP_SSID_HIDDEN}, + {"ap_channel", FORM_NAME_AP_CHANNEL}, + {"ap_authmode", FORM_NAME_AP_AUTHMODE}, + {"ap_max_conn", FORM_NAME_AP_MAX_CONN}, + {"ap_beacon_interval", FORM_NAME_AP_BEACON_INTERVAL}, + {"ap_ip_addr", FORM_NAME_AP_IP_ADDR}, + {"ap_netmask", FORM_NAME_AP_NETMASK}, + {"ap_dhcp_leases", FORM_NAME_AP_DHCP_LEASES}, + {"ap_dns", FORM_NAME_AP_DNS}, + {"done", FORM_NAME_DONE} +}; + +static form_name intern_form_name(char *str) +{ + int i; + for (i = 0; i < sizeof(form_name_table) / sizeof(form_name_table[0]); i++) { + if (!strcmp(str, form_name_table[i].str)) + return form_name_table[i].name; + } + return FORM_NAME_NONE; +} + + +static const char *http_favicon[] = { +#include "content/favicon.ico" +}; + +static int handle_favicon(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_favicon[0]) < 0) return -1; + + if (method != HTTP_METHOD_HEAD) { + if (wificfg_write_string_chunk(s, http_favicon[1], buf, len) < 0) return -1; + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + +// .value-lg{font-size:24px}.label-extra{display:block;font-style:italic;font-size:13px} +// devo: "Cache-Control: no-store\r\n" +static const char *http_style[] = { +#include "content/style.css" +}; + + +static int handle_style(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_style[0]) < 0) return -1; + + if (method != HTTP_METHOD_HEAD) { + if (wificfg_write_string_chunk(s, http_style[1], buf, len) < 0) return -1; + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + +static const char *http_script[] = { +#include "content/script.js" +}; + +static int handle_script(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_script[0]) < 0) return -1; + + if (method != HTTP_METHOD_HEAD) { + if (wificfg_write_string_chunk(s, http_script[1], buf, len) < 0) return -1; + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + + +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_redirect_header[] = "HTTP/1.1 302 \r\n" + "Location: /wificfg/\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n"; + +static int handle_wificfg_redirect(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + return wificfg_write_string(s, http_redirect_header); +} + +static int handle_ipaddr_redirect(int s, char *buf, size_t len) +{ + if (wificfg_write_string(s, "HTTP/1.1 302 \r\nLocation: http://") < 0) return -1; + + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + getsockname(s, &addr, &addr_len); + struct sockaddr_in *sa = (struct sockaddr_in *)&addr; + snprintf(buf, len, "" IPSTR "/\r\n", IP2STR((ip4_addr_t *)&sa->sin_addr.s_addr)); + if (wificfg_write_string(s, buf) < 0) return -1;; + /* Always close here - expect a new connection. */ + return wificfg_write_string(s, "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n"); +} + +int wificfg_write_html_title(int s, char *buf, size_t len, const char *str) +{ + /* Use the hostname or AP SSID as the title prefix. */ + char *hostname = NULL; + sysparam_get_string("hostname", &hostname); + if (!hostname) { + sysparam_get_string("wifi_ap_ssid", &hostname); + } + if (hostname) { + wificfg_html_escape(hostname, buf, len); + free(hostname); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (str) { + if (wificfg_write_string_chunk(s, " ", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, str, buf, len) < 0) return -1; + } + } + + return 0; +} + +static const char *http_wificfg_content[] = { +#include "content/wificfg/index.html" +}; + +static int handle_wificfg_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_wificfg_content[0], buf, len) < 0) return -1; + if (wificfg_write_html_title(s, buf, len, "Wifi Config") < 0) return -1; + if (wificfg_write_string_chunk(s, http_wificfg_content[1], buf, len) < 0) return -1; + + char *hostname = NULL; + sysparam_get_string("hostname", &hostname); + if (hostname) { + if (wificfg_write_string_chunk(s, "
Hostname
", buf, len) < 0) { + free(hostname); + return -1; + } + wificfg_html_escape(hostname, buf, len); + free(hostname); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
", buf, len) < 0) return -1; + } + + uint32_t chip_id = sdk_system_get_chip_id(); + snprintf(buf, len, "
Chip ID
%08x
", chip_id); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + snprintf(buf, len, "
Uptime
%u seconds
", + xTaskGetTickCount() * portTICK_PERIOD_MS / 1000); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + snprintf(buf, len, "
Free heap
%u bytes
", (int)xPortGetFreeHeapSize()); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + snprintf(buf, len, "
Flash ID
0x%08x
", sdk_spi_flash_get_id()); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + snprintf(buf, len, "
Flash size
%u KiB
", sdk_flashchip.chip_size >> 10); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, "
LwIP version
" LWIP_VERSION_STRING "
", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
FreeRTOS version
" tskKERNEL_VERSION_NUMBER "
", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
Newlib version
" _NEWLIB_VERSION "
", buf, len) < 0) return -1; + + enum sdk_sleep_type sleep_type = sdk_wifi_get_sleep_type(); + char *sleep_type_str = "??"; + switch (sleep_type) { + case WIFI_SLEEP_NONE: + sleep_type_str = "None"; + break; + case WIFI_SLEEP_LIGHT: + sleep_type_str = "Light"; + break; + case WIFI_SLEEP_MODEM: + sleep_type_str = "Modem"; + break; + default: + break; + } + snprintf(buf, len, "
WiFi sleep type
%s
", sleep_type_str); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + uint8_t opmode = sdk_wifi_get_opmode(); + const char *opmode_str = "??"; + switch (opmode) { + case NULL_MODE: + opmode_str = "Null"; + break; + case STATION_MODE: + opmode_str = "Station"; + break; + case SOFTAP_MODE: + opmode_str = "SoftAP"; + break; + case STATIONAP_MODE: + opmode_str = "StationAP"; + break; + default: + break; + } + snprintf(buf, len, "
OpMode
%s
", opmode_str); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (opmode > NULL_MODE) { + snprintf(buf, len, "
WiFi channel
%u
", sdk_wifi_get_channel()); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + const char *phy_mode_str = "??"; + switch (sdk_wifi_get_phy_mode()) { + case PHY_MODE_11B: + phy_mode_str = "11b"; + break; + case PHY_MODE_11G: + phy_mode_str = "11g"; + break; + case PHY_MODE_11N: + phy_mode_str = "11n"; + break; + default: + break; + } + snprintf(buf, len, "
WiFi physical mode
%s
", phy_mode_str); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (opmode == STATION_MODE || opmode == STATIONAP_MODE) { + uint8_t hwaddr[6]; + if (sdk_wifi_get_macaddr(STATION_IF, hwaddr)) { + if (wificfg_write_string_chunk(s, "
Station MAC address
", buf, len) < 0) return -1; + snprintf(buf, len, "
" MACSTR "
", MAC2STR(hwaddr)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + struct ip_info info; + if (sdk_wifi_get_ip_info(STATION_IF, &info)) { + if (wificfg_write_string_chunk(s, "
Station IP address
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR "
", IP2STR(&info.ip)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
Station netmask
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR "
", IP2STR(&info.netmask)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
Station gateway
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR "
", IP2STR(&info.gw)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + } + + if (opmode == SOFTAP_MODE || opmode == STATIONAP_MODE) { + uint8_t hwaddr[6]; + if (sdk_wifi_get_macaddr(SOFTAP_IF, hwaddr)) { + if (wificfg_write_string_chunk(s, "
AP MAC address
", buf, len) < 0) return -1; + snprintf(buf, len, "
" MACSTR "
", MAC2STR(hwaddr)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + struct ip_info info; + if (sdk_wifi_get_ip_info(SOFTAP_IF, &info)) { + if (wificfg_write_string_chunk(s, "
AP IP address
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR "
", IP2STR(&info.ip)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
AP netmask
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR "
", IP2STR(&info.netmask)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, "
AP gateway
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR "
", IP2STR(&info.gw)); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + } + + struct sockaddr addr; + socklen_t addr_len = sizeof(addr); + getpeername(s, (struct sockaddr*)&addr, &addr_len); + + if (addr.sa_family == AF_INET) { + struct sockaddr_in *sa = (struct sockaddr_in *)&addr; + if (wificfg_write_string_chunk(s, "
Peer address
", buf, len) < 0) return -1; + snprintf(buf, len, "
" IPSTR " : %u
", + 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, http_wificfg_content[2], buf, len) < 0) return -1; + + char *password = NULL; + sysparam_get_string("cfg_password", &password); + if (password) { + wificfg_html_escape(password, buf, len); + free(password); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wificfg_content[3], buf, len) < 0) return -1; + + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + +static int handle_wificfg_index_post(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + if (content_type != HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED) { + return wificfg_write_string(s, "HTTP/1.1 400 \r\n" + "Content-Type: text/html\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n\r\n"); + } + + size_t rem = content_length; + bool valp = false; + + while (rem > 0) { + int r = wificfg_form_name_value(s, &valp, &rem, buf, len); + + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + form_name name = intern_form_name(buf); + + if (valp) { + int r = wificfg_form_name_value(s, NULL, &rem, buf, len); + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + switch (name) { + case FORM_NAME_CFG_ENABLE: { + uint8_t enable = strtoul(buf, NULL, 10) != 0; + sysparam_set_int8("cfg_enable", enable); + break; + } + case FORM_NAME_CFG_PASSWORD: + sysparam_set_string("cfg_password", buf); + break; + default: + break; + } + } + } + + return wificfg_write_string(s, http_redirect_header); +} + +static const char *http_wifi_station_content[] = { +#include "content/wificfg/sta.html" +}; + +static int handle_wifi_station(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_wifi_station_content[0], buf, len) < 0) return -1; + if (wificfg_write_html_title(s, buf, len, "Wifi station") < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_station_content[1], buf, len) < 0) return -1; + + int8_t wifi_sta_enable = 1; + sysparam_get_int8("wifi_sta_enable", &wifi_sta_enable); + if (wifi_sta_enable && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_station_content[2], buf, len) < 0) return -1; + + int8_t wifi_sta_disabled_restarts = 0; + sysparam_get_int8("wifi_sta_disabled_restarts", &wifi_sta_disabled_restarts); + snprintf(buf, len, "%u", wifi_sta_disabled_restarts); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_station_content[3], buf, len) < 0) return -1; + + char *wifi_sta_ssid = NULL; + sysparam_get_string("wifi_sta_ssid", &wifi_sta_ssid); + if (wifi_sta_ssid) { + wificfg_html_escape(wifi_sta_ssid, buf, len); + free(wifi_sta_ssid); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_station_content[4], buf, len) < 0) return -1; + + char *wifi_sta_password = NULL; + sysparam_get_string("wifi_sta_password", &wifi_sta_password); + if (wifi_sta_password) { + wificfg_html_escape(wifi_sta_password, buf, len); + free(wifi_sta_password); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_station_content[5], buf, len) < 0) return -1; + + char *hostname = NULL; + sysparam_get_string("hostname", &hostname); + if (hostname) { + wificfg_html_escape(hostname, buf, len); + free(hostname); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_station_content[6], buf, len) < 0) return -1; + + int8_t wifi_sta_dhcp = 1; + sysparam_get_int8("wifi_sta_dhcp", &wifi_sta_dhcp); + if (wifi_sta_dhcp && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_station_content[7], buf, len) < 0) return -1; + if (!wifi_sta_dhcp && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_station_content[8], buf, len) < 0) return -1; + + char *wifi_sta_ip_addr = NULL; + sysparam_get_string("wifi_sta_ip_addr", &wifi_sta_ip_addr); + if (wifi_sta_ip_addr) { + wificfg_html_escape(wifi_sta_ip_addr, buf, len); + free(wifi_sta_ip_addr); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_station_content[9], buf, len) < 0) return -1; + + char *wifi_sta_netmask = NULL; + sysparam_get_string("wifi_sta_netmask", &wifi_sta_netmask); + if (wifi_sta_netmask) { + wificfg_html_escape(wifi_sta_netmask, buf, len); + free(wifi_sta_netmask); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_station_content[10], buf, len) < 0) return -1; + + char *wifi_sta_gateway = NULL; + sysparam_get_string("wifi_sta_gateway", &wifi_sta_gateway); + if (wifi_sta_gateway) { + wificfg_html_escape(wifi_sta_gateway, buf, len); + free(wifi_sta_gateway); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_station_content[11], buf, len) < 0) return -1; + + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + +static int handle_wifi_station_post(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + if (content_type != HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED) { + return wificfg_write_string(s, "HTTP/1.1 400 \r\n" + "Content-Type: text/html\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n\r\n"); + } + + size_t rem = content_length; + bool valp = false; + + /* Delay committing some values until all have been read. */ + bool done = false; + uint8_t sta_enable = 0; + + while (rem > 0) { + int r = wificfg_form_name_value(s, &valp, &rem, buf, len); + + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + form_name name = intern_form_name(buf); + + if (valp) { + int r = wificfg_form_name_value(s, NULL, &rem, buf, len); + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + switch (name) { + case FORM_NAME_STA_ENABLE: { + sta_enable = strtoul(buf, NULL, 10) != 0; + break; + } + case FORM_NAME_STA_DISABLED_RESTARTS: { + uint32_t restarts = strtoul(buf, NULL, 10); + if (restarts <= 255) + sysparam_set_int8("wifi_sta_disabled_restarts", restarts); + break; + } + case FORM_NAME_STA_SSID: + sysparam_set_string("wifi_sta_ssid", buf); + break; + case FORM_NAME_STA_PASSWORD: + sysparam_set_string("wifi_sta_password", buf); + break; + case FORM_NAME_HOSTNAME: + sysparam_set_string("hostname", buf); + break; + case FORM_NAME_STA_DHCP: { + uint8_t enable = strtoul(buf, NULL, 10) != 0; + sysparam_set_int8("wifi_sta_dhcp", enable); + break; + } + case FORM_NAME_STA_IP_ADDR: + sysparam_set_string("wifi_sta_ip_addr", buf); + break; + case FORM_NAME_STA_NETMASK: + sysparam_set_string("wifi_sta_netmask", buf); + break; + case FORM_NAME_STA_GATEWAY: + sysparam_set_string("wifi_sta_gateway", buf); + break; + case FORM_NAME_DONE: + done = true; + break; + default: + break; + } + } + } + + if (done) { + sysparam_set_int8("wifi_sta_enable", sta_enable); + } + + return wificfg_write_string(s, http_redirect_header); +} + +static const char *http_wifi_ap_content[] = { +#include "content/wificfg/ap.html" +}; + +static int handle_wifi_ap(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_wifi_ap_content[0], buf, len) < 0) return -1; + if (wificfg_write_html_title(s, buf, len, "Wifi access point") < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_ap_content[1], buf, len) < 0) return -1; + + int8_t wifi_ap_enable = 1; + sysparam_get_int8("wifi_ap_enable", &wifi_ap_enable); + if (wifi_ap_enable && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[2], buf, len) < 0) return -1; + + int8_t wifi_ap_disable_if_sta = 1; + sysparam_get_int8("wifi_ap_disable_if_sta", &wifi_ap_disable_if_sta); + if (wifi_ap_disable_if_sta && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[3], buf, len) < 0) return -1; + + int8_t wifi_ap_disabled_restarts = 0; + sysparam_get_int8("wifi_ap_disabled_restarts", &wifi_ap_disabled_restarts); + snprintf(buf, len, "%u", wifi_ap_disabled_restarts); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[4], buf, len) < 0) return -1; + + char *wifi_ap_ssid = NULL; + sysparam_get_string("wifi_ap_ssid", &wifi_ap_ssid); + if (wifi_ap_ssid) { + wificfg_html_escape(wifi_ap_ssid, buf, len); + free(wifi_ap_ssid); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[5], buf, len) < 0) return -1; + + char *wifi_ap_password = NULL; + sysparam_get_string("wifi_ap_password", &wifi_ap_password); + if (wifi_ap_password) { + wificfg_html_escape(wifi_ap_password, buf, len); + free(wifi_ap_password); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[6], buf, len) < 0) return -1; + + int8_t wifi_ap_ssid_hidden = 0; + sysparam_get_int8("wifi_ap_ssid_hidden", &wifi_ap_ssid_hidden); + if (wifi_ap_ssid_hidden && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[7], buf, len) < 0) return -1; + + int8_t wifi_ap_channel = 6; + sysparam_get_int8("wifi_ap_channel", &wifi_ap_channel); + snprintf(buf, len, "%u", wifi_ap_channel); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[8], buf, len) < 0) return -1; + + int8_t wifi_ap_authmode = 4; + sysparam_get_int8("wifi_ap_authmode", &wifi_ap_authmode); + if (wifi_ap_authmode == 0 && wificfg_write_string_chunk(s, " selected", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_ap_content[9], buf, len) < 0) return -1; + if (wifi_ap_authmode == 1 && wificfg_write_string_chunk(s, " selected", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_ap_content[10], buf, len) < 0) return -1; + if (wifi_ap_authmode == 2 && wificfg_write_string_chunk(s, " selected", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_ap_content[11], buf, len) < 0) return -1; + if (wifi_ap_authmode == 3 && wificfg_write_string_chunk(s, " selected", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_ap_content[12], buf, len) < 0) return -1; + if (wifi_ap_authmode == 4 && wificfg_write_string_chunk(s, " selected", buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[13], buf, len) < 0) return -1; + + int8_t wifi_ap_max_conn = 3; + sysparam_get_int8("wifi_ap_max_conn", &wifi_ap_max_conn); + snprintf(buf, len, "%u", wifi_ap_max_conn); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[14], buf, len) < 0) return -1; + + int32_t wifi_ap_beacon_interval = 100; + sysparam_get_int32("wifi_ap_beacon_interval", &wifi_ap_beacon_interval); + snprintf(buf, len, "%u", wifi_ap_beacon_interval); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[15], buf, len) < 0) return -1; + + char *wifi_ap_ip_addr = NULL; + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + if (wifi_ap_ip_addr) { + wificfg_html_escape(wifi_ap_ip_addr, buf, len); + free(wifi_ap_ip_addr); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[16], buf, len) < 0) return -1; + + char *wifi_ap_netmask = NULL; + sysparam_get_string("wifi_ap_netmask", &wifi_ap_netmask); + if (wifi_ap_netmask) { + wificfg_html_escape(wifi_ap_netmask, buf, len); + free(wifi_ap_netmask); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[17], buf, len) < 0) return -1; + + int8_t wifi_ap_dhcp_leases = 4; + sysparam_get_int8("wifi_ap_dhcp_leases", &wifi_ap_dhcp_leases); + snprintf(buf, len, "%u", wifi_ap_dhcp_leases); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) return -1; + + if (wificfg_write_string_chunk(s, http_wifi_ap_content[18], buf, len) < 0) return -1; + + int8_t wifi_ap_dns = 1; + sysparam_get_int8("wifi_ap_dns", &wifi_ap_dns); + if (wifi_ap_dns && wificfg_write_string_chunk(s, "checked", buf, len) < 0) return -1; + if (wificfg_write_string_chunk(s, http_wifi_ap_content[19], buf, len) < 0) return -1; + + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + +static int handle_wifi_ap_post(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + if (content_type != HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED) { + return wificfg_write_string(s, "HTTP/1.1 400 \r\n" + "Content-Type: text/html\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n\r\n"); + } + + size_t rem = content_length; + bool valp = false; + + /* Delay committing some values until all have been read. */ + bool done = false; + uint8_t ap_enable = 0; + uint8_t ap_disable_if_sta = 0; + uint8_t ssid_hidden = 0; + uint8_t dns_enable = 0; + + while (rem > 0) { + int r = wificfg_form_name_value(s, &valp, &rem, buf, len); + + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + form_name name = intern_form_name(buf); + + if (valp) { + int r = wificfg_form_name_value(s, NULL, &rem, buf, len); + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + switch (name) { + case FORM_NAME_AP_ENABLE: { + ap_enable = strtoul(buf, NULL, 10) != 0; + break; + } + case FORM_NAME_AP_DISABLE_IF_STA: { + ap_disable_if_sta = strtoul(buf, NULL, 10) != 0; + break; + } + case FORM_NAME_AP_DISABLED_RESTARTS: { + uint32_t restarts = strtoul(buf, NULL, 10); + if (restarts <= 255) + sysparam_set_int8("wifi_ap_disabled_restarts", restarts); + break; + } + case FORM_NAME_AP_SSID: + sysparam_set_string("wifi_ap_ssid", buf); + break; + case FORM_NAME_AP_PASSWORD: + sysparam_set_string("wifi_ap_password", buf); + break; + case FORM_NAME_AP_SSID_HIDDEN: { + ssid_hidden = strtoul(buf, NULL, 10) != 0; + break; + } + case FORM_NAME_AP_CHANNEL: { + uint32_t channel = strtoul(buf, NULL, 10); + if (channel >= 1 && channel <= 14) + sysparam_set_int8("wifi_ap_channel", channel); + break; + } + case FORM_NAME_AP_AUTHMODE: { + uint32_t mode = strtoul(buf, NULL, 10); + if (mode >= 0 && mode <= 5) + sysparam_set_int8("wifi_ap_authmode", mode); + break; + } + case FORM_NAME_AP_MAX_CONN: { + uint32_t max_conn = strtoul(buf, NULL, 10); + if (max_conn >= 0 && max_conn <= 8) + sysparam_set_int8("wifi_ap_max_conn", max_conn); + break; + } + case FORM_NAME_AP_BEACON_INTERVAL: { + uint32_t interval = strtoul(buf, NULL, 10); + if (interval >= 0 && interval <= 10000) + sysparam_set_int32("wifi_ap_beacon_interval", interval); + break; + } + case FORM_NAME_AP_IP_ADDR: + sysparam_set_string("wifi_ap_ip_addr", buf); + break; + case FORM_NAME_AP_NETMASK: + sysparam_set_string("wifi_ap_netmask", buf); + break; + case FORM_NAME_AP_DHCP_LEASES: { + uint32_t leases = strtoul(buf, NULL, 10); + if (leases >= 0 && leases <= 16) + sysparam_set_int8("wifi_ap_dhcp_leases", leases); + break; + } + case FORM_NAME_AP_DNS: { + dns_enable = strtoul(buf, NULL, 10) != 0; + break; + } + case FORM_NAME_DONE: + done = true; + break; + default: + break; + } + } + } + + if (done) { + sysparam_set_int8("wifi_ap_enable", ap_enable); + sysparam_set_int8("wifi_ap_disable_if_sta", ap_disable_if_sta); + sysparam_set_int8("wifi_ap_ssid_hidden", ssid_hidden); + sysparam_set_int8("wifi_ap_dns", dns_enable); + } + + return wificfg_write_string(s, http_redirect_header); +} + +static bool got_sta_connect = false; +void wificfg_got_sta_connect() +{ + /* Only process this once, to not continue adjusting the settings. */ + if (got_sta_connect) { + return; + } + got_sta_connect = true; + + /* Skip if AP not even enabled. */ + int8_t wifi_ap_enable = 1; + sysparam_get_int8("wifi_ap_enable", &wifi_ap_enable); + if (!wifi_ap_enable) { + return; + } + + int8_t wifi_ap_disable_if_sta = 1; + sysparam_get_int8("wifi_ap_disable_if_sta", &wifi_ap_disable_if_sta); + + if (wifi_ap_disable_if_sta) { + int8_t wifi_ap_disabled_restarts = 0; + sysparam_get_int8("wifi_ap_disabled_restarts", &wifi_ap_disabled_restarts); + if (wifi_ap_disabled_restarts == 0) { + sysparam_set_int8("wifi_ap_disabled_restarts", 1); + } + } +} + +static int handle_restart_post(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + wificfg_write_string(s, http_redirect_header); + close(s); + vTaskDelay(2000 / portTICK_PERIOD_MS); + sdk_system_restart(); + return 0; +} + +static int handle_erase_post(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + wificfg_write_string(s, http_redirect_header); + close(s); + vTaskDelay(2000 / portTICK_PERIOD_MS); + + /* + * Erase the area starting from the sysparams to the end of the flash. + * Configuration information may be in the sdk parameter area too, which is + * in these sectors. + */ + uint32_t num_sectors = 5 + DEFAULT_SYSPARAM_SECTORS; + uint32_t start = sdk_flashchip.chip_size - num_sectors * sdk_flashchip.sector_size; + uint32_t i; + vPortEnterCritical(); + for (i = 0; i < num_sectors; i++) { + spiflash_erase_sector(start + i * sdk_flashchip.sector_size); + } + sdk_system_restart(); + return 0; +} + +/* Minimal not-found response. */ +static const char not_found_header[] = "HTTP/1.1 404 \r\n" + "Content-Type: text/html; charset=utf-8\r\n" + "Cache-Control: no-store\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n" + "\r\n"; + +static const char *http_wificfg_challenge_content[] = { +#include "content/challenge.html" +}; + +static int handle_wificfg_challenge(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_wificfg_challenge_content[0], buf, len) < 0) return -1; + if (wificfg_write_html_title(s, buf, len, "Challenge") < 0) return -1; + if (wificfg_write_string_chunk(s, http_wificfg_challenge_content[1], buf, len) < 0) return -1; + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} + +static int handle_wificfg_challenge_post(int s, wificfg_method method, + uint32_t content_length, + wificfg_content_type content_type, + char *buf, size_t len) +{ + if (content_type != HTTP_CONTENT_TYPE_WWW_FORM_URLENCODED) { + return wificfg_write_string(s, "HTTP/1.1 400 \r\n" + "Content-Type: text/html\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n\r\n"); + } + size_t rem = content_length; + bool valp = false; + + int8_t enable = 1; + sysparam_get_int8("cfg_enable", &enable); + char *password = NULL; + sysparam_get_string("cfg_password", &password); + + if (!enable && password && strlen(password)) { + while (rem > 0) { + int r = wificfg_form_name_value(s, &valp, &rem, buf, len); + + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + form_name name = intern_form_name(buf); + + if (valp) { + int r = wificfg_form_name_value(s, NULL, &rem, buf, len); + if (r < 0) { + break; + } + + wificfg_form_url_decode(buf); + + switch (name) { + case FORM_NAME_CFG_PASSWORD: + if (strcmp(password, buf) == 0) + sysparam_set_int8("cfg_enable", 1); + break; + default: + break; + } + } + } + } + + if (password) + free(password); + + return wificfg_write_string(s, http_redirect_header); +} + +#ifdef configUSE_TRACE_FACILITY +static const char *http_tasks_content[] = { +#include "content/tasks.html" +}; + +static int handle_tasks(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_tasks_content[0], buf, len) < 0) return -1; + if (wificfg_write_html_title(s, buf, len, "Tasks") < 0) return -1; + if (wificfg_write_string_chunk(s, http_tasks_content[1], buf, len) < 0) return -1; + int num_tasks = uxTaskGetNumberOfTasks(); + TaskStatus_t *task_status = pvPortMalloc(num_tasks * sizeof(TaskStatus_t)); + + if (task_status != NULL) { + int i; + + if (wificfg_write_string_chunk(s, "", buf, len) < 0) { + free(task_status); + return -1; + } + + /* Generate the (binary) data. */ + num_tasks = uxTaskGetSystemState(task_status, num_tasks, NULL); + + /* Create a human readable table from the binary data. */ + for(i = 0; i < num_tasks; i++) { + char cStatus; + switch(task_status[i].eCurrentState) { + case eRunning: cStatus = '*'; break; + case eReady: cStatus = 'R'; break; + case eBlocked: cStatus = 'B'; break; + case eSuspended: cStatus = 'S'; break; + case eDeleted: cStatus = 'D'; break; + default: cStatus = '?'; break; + } + + snprintf(buf, len, "", task_status[i].pcTaskName); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) { + free(task_status); + return -1; + } + snprintf(buf, len, "", + (unsigned int)task_status[i].xTaskNumber, + cStatus); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) { + free(task_status); + return -1; + } + snprintf(buf, len, "", + (unsigned int)task_status[i].uxCurrentPriority, + (unsigned int)task_status[i].uxBasePriority); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) { + free(task_status); + return -1; + } + snprintf(buf, len, "", + (unsigned int)task_status[i].ulRunTimeCounter, + (unsigned int)task_status[i].usStackHighWaterMark); + if (wificfg_write_string_chunk(s, buf, buf, len) < 0) { + free(task_status); + return -1; + } + } + + free(task_status); + + if (wificfg_write_string_chunk(s, "
Task nameTask numberStatusPriorityBase priorityRuntimeStack high-water
%s%u%c%u%u%u%u
", buf, len) < 0) return -1; + } + + if (wificfg_write_string_chunk(s, http_tasks_content[2], buf, len) < 0) return -1; + if (wificfg_write_chunk_end(s) < 0) return -1; + } + return 0; +} +#endif /* configUSE_TRACE_FACILITY */ + +static const wificfg_dispatch wificfg_dispatch_list[] = { + {"/favicon.ico", HTTP_METHOD_GET, handle_favicon, false}, + {"/style.css", HTTP_METHOD_GET, handle_style, false}, + {"/script.js", HTTP_METHOD_GET, handle_script, false}, + {"/", HTTP_METHOD_GET, handle_wificfg_redirect, false}, + {"/index.html", HTTP_METHOD_GET, handle_wificfg_redirect, false}, + {"/wificfg/", HTTP_METHOD_GET, handle_wificfg_index, true}, + {"/wificfg/", HTTP_METHOD_POST, handle_wificfg_index_post, true}, + {"/wificfg/sta.html", HTTP_METHOD_GET, handle_wifi_station, true}, + {"/wificfg/sta.html", HTTP_METHOD_POST, handle_wifi_station_post, true}, + {"/wificfg/ap.html", HTTP_METHOD_GET, handle_wifi_ap, true}, + {"/wificfg/ap.html", HTTP_METHOD_POST, handle_wifi_ap_post, true}, + {"/challenge.html", HTTP_METHOD_GET, handle_wificfg_challenge, false}, + {"/challenge.html", HTTP_METHOD_POST, handle_wificfg_challenge_post, false}, + {"/wificfg/restart.html", HTTP_METHOD_POST, handle_restart_post, true}, + {"/wificfg/erase.html", HTTP_METHOD_POST, handle_erase_post, true}, +#ifdef configUSE_TRACE_FACILITY + {"/tasks", HTTP_METHOD_GET, handle_tasks, false}, + {"/tasks.html", HTTP_METHOD_GET, handle_tasks, false}, +#endif /* configUSE_TRACE_FACILITY */ + {NULL, HTTP_METHOD_ANY, NULL} +}; + +static const wificfg_dispatch wificfg_challenge_dispatch = {"/challenge.html", HTTP_METHOD_GET, handle_wificfg_challenge, false}; + +typedef struct { + int32_t port; + /* + * Two dispatch lists. First is used for the config pages. Second + * can be used to extend the pages handled in app code. + */ + const wificfg_dispatch *wificfg_dispatch; + const wificfg_dispatch *dispatch; +} server_params; + +/* + * The http server uses a single thread to service all requests, one request at + * a time, to keep peak resource usage to a minimum. Keeping connections open + * would cause delays switching between connections. Thus it closes the + * connection after each response. + * + * To help avoid the resource usage of connections in the time-wait state, the + * server asks the client to initiate the connection close and waits a short + * period for it to do so before closing the connection itself. + * + * The response length is always well defined, either sending the content-length + * header or using chunk transfer encoding. Thus the client knows the end of + * responses without the server having to close the connection, and this allows + * the client to close the connection. + * + * Always closing the connection also allows the connection-close header to be + * statically bundled in with the response. + */ +static void server_task(void *pvParameters) +{ + server_params *params = pvParameters; + + struct sockaddr_in serv_addr; + int listenfd = socket(AF_INET, SOCK_STREAM, 0); + memset(&serv_addr, '0', sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(params->port); + bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); + listen(listenfd, 2); + + for (;;) { + int s = accept(listenfd, (struct sockaddr *)NULL, (socklen_t *)NULL); + if (s >= 0) { + const struct timeval timeout = { 10, 0 }; /* 10 second timeout */ + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); + + /* Buffer for reading the request and headers and the post method + * names and values. Also used for building dynamically generated + * responses. */ + char buf[HTTP_BUFFER_SIZE]; + + for (;;) { + /* Read the request line */ + int request_line_size = read_crlf_line(s, buf, sizeof(buf)); + if (request_line_size < 5) { + break; + } + + /* Parse the http method, path, and protocol version. */ + char *method_end = skip_to_whitespace(buf); + char *path_string = skip_whitespace(method_end); + *method_end = 0; + wificfg_method method = intern_http_method(buf); + char *path_end = skip_to_whitespace(path_string); + *path_end = 0; + + /* Dispatch to separate functions to handle the requests. */ + const wificfg_dispatch *match = NULL; + const wificfg_dispatch *dispatch; + + /* + * Check the optional application supplied dispatch table + * first to allow overriding the wifi config paths. + */ + if (params->dispatch) { + for (dispatch = params->dispatch; dispatch->path != NULL; dispatch++) { + if (strcmp(path_string, dispatch->path) == 0 && + (dispatch->method == HTTP_METHOD_ANY || + method == dispatch->method)) { + match = dispatch; + break; + } + } + } + + if (!match) { + for (dispatch = params->wificfg_dispatch; dispatch->path != NULL; dispatch++) { + if (strcmp(path_string, dispatch->path) == 0 && + (dispatch->method == HTTP_METHOD_ANY || + method == dispatch->method)) { + match = dispatch; + break; + } + } + } + + if (match && match->secure) { + /* A secure url so check if enabled. */ + int8_t enable = 1; + sysparam_get_int8("cfg_enable", &enable); + if (!enable) { + /* Is there a recovery password? */ + char *password = NULL; + sysparam_get_string("cfg_password", &password); + if (password && strlen(password) > 0) { + match = &wificfg_challenge_dispatch; + } else { + match = NULL; + } + if (password) + free(password); + } + } + + /* Read the headers, noting some of interest. */ + wificfg_content_type content_type = HTTP_CONTENT_TYPE_OTHER; + bool connection_close = false; + bool hostp = false; + uint32_t host = IPADDR_NONE; + long content_length = 0; + + for (;;) { + int header_length = read_crlf_line(s, buf, sizeof(buf)); + if (header_length <= 0) + break; + + char *name_end = buf; + for (; ; name_end++) { + char c = *name_end; + if (!c || c == ':') + break; + } + if (*name_end == ':') { + char *value = name_end + 1; + *name_end = 0; + http_header header = intern_http_header(buf); + value = skip_whitespace(value); + switch (header) { + case HTTP_HEADER_HOST: + hostp = true; + host = ipaddr_addr(value); + break; + case HTTP_HEADER_CONTENT_LENGTH: + content_length = strtoul(value, NULL, 10); + break; + case HTTP_HEADER_CONTENT_TYPE: + content_type = intern_http_content_type(value); + break; + case HTTP_HEADER_CONNECTION: + connection_close = strcmp(value, "close") == 0; + break; + default: + break; + } + } + } + + if (hostp && host == IPADDR_NONE) { + /* Redirect to an IP address. */ + handle_ipaddr_redirect(s, buf, sizeof(buf)); + /* Close the connection. */ + break; + } else if (match) { + if ((*match->handler)(s, method, content_length, content_type, buf, sizeof(buf)) < 0) break; + } else { + if (wificfg_write_string(s, not_found_header) < 0) break; + } + + /* + * At this point the client is expected to close the connection, + * so wait briefly for it to do so before giving up. While here + * consume any excess input to avoid a connection reset - this + * can happen if the handler aborted early. + */ + const struct timeval timeout1 = { 1, 0 }; /* 1 second timeout */ + setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout1, sizeof(timeout1)); + size_t len; + for (len = 0; len < 4096; len++) { + char c; + int res = read(s, &c, 1); + if (res != 1) break; + } + + if (connection_close) + break; + + /* Close anyway. */ + break; + } + + close(s); + + if (sdk_wifi_station_get_connect_status() == STATION_GOT_IP) { + wificfg_got_sta_connect(); + } + } + } +} + + +static void dns_task(void *pvParameters) +{ + char *wifi_ap_ip_addr = NULL; + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + if (!wifi_ap_ip_addr) { + printf("dns: no ip address\n"); + vTaskDelete(NULL); + } + ip4_addr_t server_addr; + server_addr.addr = ipaddr_addr(wifi_ap_ip_addr); + + struct sockaddr_in serv_addr; + int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + memset(&serv_addr, '0', sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + serv_addr.sin_port = htons(53); + bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); + + const struct ifreq ifreq0 = { "en0" }; + const struct ifreq ifreq1 = { "en1" }; + lwip_setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, + sdk_wifi_get_opmode() == STATIONAP_MODE ? &ifreq1 : &ifreq0, + sizeof(ifreq0)); + + for (;;) { + char buffer[96]; + struct sockaddr src_addr; + socklen_t src_addr_len = sizeof(src_addr); + size_t count = recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&src_addr, &src_addr_len); + + /* Drop messages that are too large to send a response in the buffer */ + if (count > 0 && count <= sizeof(buffer) - 16 && src_addr.sa_family == AF_INET) { + size_t qname_len = strlen(buffer + 12) + 1; + uint32_t reply_len = 2 + 10 + qname_len + 16 + 4; + + char *head = buffer + 2; + *head++ = 0x80; // Flags + *head++ = 0x00; + *head++ = 0x00; // Q count + *head++ = 0x01; + *head++ = 0x00; // A count + *head++ = 0x01; + *head++ = 0x00; // Auth count + *head++ = 0x00; + *head++ = 0x00; // Add count + *head++ = 0x00; + head += qname_len; + *head++ = 0x00; // Q type + *head++ = 0x01; + *head++ = 0x00; // Q class + *head++ = 0x01; + *head++ = 0xC0; // LBL offs + *head++ = 0x0C; + *head++ = 0x00; // Type + *head++ = 0x01; + *head++ = 0x00; // Class + *head++ = 0x01; + *head++ = 0x00; // TTL + *head++ = 0x00; + *head++ = 0x00; + *head++ = 0x78; + *head++ = 0x00; // RD len + *head++ = 0x04; + *head++ = ip4_addr1(&server_addr); + *head++ = ip4_addr2(&server_addr); + *head++ = ip4_addr3(&server_addr); + *head++ = ip4_addr4(&server_addr); + + sendto(fd, buffer, reply_len, 0, &src_addr, src_addr_len); + } + } +} + + +void wificfg_init(uint32_t port, const wificfg_dispatch *dispatch) +{ + char *wifi_sta_ssid = NULL; + char *wifi_sta_password = NULL; + char *wifi_ap_ssid = NULL; + char *wifi_ap_password = NULL; + + uint32_t base_addr; + uint32_t num_sectors; + if (sysparam_get_info(&base_addr, &num_sectors) != SYSPARAM_OK) { + printf("Warning: WiFi config, sysparam not initialized\n"); + return; + } + + sysparam_get_string("wifi_ap_ssid", &wifi_ap_ssid); + sysparam_get_string("wifi_ap_password", &wifi_ap_password); + sysparam_get_string("wifi_sta_ssid", &wifi_sta_ssid); + sysparam_get_string("wifi_sta_password", &wifi_sta_password); + + int8_t wifi_sta_enable = 1; + int8_t wifi_ap_enable = 1; + sysparam_get_int8("wifi_sta_enable", &wifi_sta_enable); + sysparam_get_int8("wifi_ap_enable", &wifi_ap_enable); + + int8_t wifi_sta_disabled_restarts = 0; + sysparam_get_int8("wifi_sta_disabled_restarts", &wifi_sta_disabled_restarts); + if (wifi_sta_disabled_restarts > 0) { + wifi_sta_enable = 0; + wifi_sta_disabled_restarts--; + sysparam_set_int8("wifi_sta_disabled_restarts", wifi_sta_disabled_restarts); + } + + int8_t wifi_ap_disabled_restarts = 0; + sysparam_get_int8("wifi_ap_disabled_restarts", &wifi_ap_disabled_restarts); + if (wifi_ap_disabled_restarts > 0) { + wifi_ap_enable = 0; + wifi_ap_disabled_restarts--; + sysparam_set_int8("wifi_ap_disabled_restarts", wifi_ap_disabled_restarts); + } + + /* Validate the configuration. */ + + if (wifi_sta_enable && (!wifi_sta_ssid || !wifi_sta_password || + strlen(wifi_sta_ssid) < 1 || + strlen(wifi_sta_ssid) > 32 || + !wifi_sta_password || + strlen(wifi_sta_password) < 8 || + strlen(wifi_sta_password) >= 64)) { + wifi_sta_enable = 0; + } + + if (wifi_ap_enable) { + /* Default AP ssid and password. */ + if (!wifi_ap_ssid && wificfg_default_ssid) { + uint8_t macaddr[6]; + char ssid[32]; + sdk_wifi_get_macaddr(1, macaddr); + snprintf(ssid, sizeof(ssid), wificfg_default_ssid, macaddr[3], + macaddr[4], macaddr[5]); + sysparam_set_string("wifi_ap_ssid", ssid); + sysparam_get_string("wifi_ap_ssid", &wifi_ap_ssid); + + if (!wifi_ap_password && wificfg_default_password) { + sysparam_set_string("wifi_ap_password", wificfg_default_password); + sysparam_get_string("wifi_ap_password", &wifi_ap_password); + } + } + + /* If the ssid and password are not valid then disable the AP interface. */ + if (!wifi_ap_ssid || strlen(wifi_ap_ssid) < 1 || strlen(wifi_ap_ssid) >= 32 || + !wifi_ap_password || strlen(wifi_ap_ssid) < 8 || strlen(wifi_ap_password) >= 64) { + wifi_ap_enable = 0; + } + } + + int8_t wifi_mode = NULL_MODE; + if (wifi_sta_enable && wifi_ap_enable) + wifi_mode = STATIONAP_MODE; + else if (wifi_sta_enable) + wifi_mode = STATION_MODE; + else + wifi_mode = SOFTAP_MODE; + sdk_wifi_set_opmode(wifi_mode); + + if (wifi_sta_enable) { + /* Default a hostname. */ + char *hostname = NULL; + sysparam_get_string("hostname", &hostname); + if (!hostname && wificfg_default_hostname) { + uint8_t macaddr[6]; + char name[32]; + sdk_wifi_get_macaddr(1, macaddr); + snprintf(name, sizeof(name), wificfg_default_hostname, macaddr[3], + macaddr[4], macaddr[5]); + sysparam_set_string("hostname", name); + } + if (hostname) { + free(hostname); + } + + struct sdk_station_config config; + strcpy((char *)config.ssid, wifi_sta_ssid); + strcpy((char *)config.password, wifi_sta_password); + config.bssid_set = 0; + + int8_t wifi_sta_dhcp = 1; + sysparam_get_int8("wifi_sta_dhcp", &wifi_sta_dhcp); + + if (!wifi_sta_dhcp) { + char *wifi_sta_ip_addr = NULL; + char *wifi_sta_netmask = NULL; + char *wifi_sta_gateway = NULL; + sysparam_get_string("wifi_sta_ip_addr", &wifi_sta_ip_addr); + sysparam_get_string("wifi_sta_netmask", &wifi_sta_netmask); + sysparam_get_string("wifi_sta_gateway", &wifi_sta_gateway); + + if (wifi_sta_ip_addr && strlen(wifi_sta_ip_addr) > 4 && + wifi_sta_netmask && strlen(wifi_sta_netmask) > 4 && + wifi_sta_gateway && strlen(wifi_sta_gateway) > 4) { + sdk_wifi_station_dhcpc_stop(); + struct ip_info info; + memset(&info, 0x0, sizeof(info)); + info.ip.addr = ipaddr_addr(wifi_sta_ip_addr); + info.netmask.addr = ipaddr_addr(wifi_sta_netmask); + info.gw.addr = ipaddr_addr(wifi_sta_gateway); + sdk_wifi_set_ip_info(STATION_IF, &info); + } + if (wifi_sta_ip_addr) free(wifi_sta_ip_addr); + if (wifi_sta_netmask) free(wifi_sta_netmask); + if (wifi_sta_gateway) free(wifi_sta_gateway); + } + + sdk_wifi_station_set_config(&config); + } + + if (wifi_ap_enable) { + /* Read and validate paramenters. */ + int8_t wifi_ap_ssid_hidden = 0; + sysparam_get_int8("wifi_ap_ssid_hidden", &wifi_ap_ssid_hidden); + if (wifi_ap_ssid_hidden < 0 || wifi_ap_ssid_hidden > 1) + wifi_ap_ssid_hidden = 1; + + int8_t wifi_ap_channel = 6; + sysparam_get_int8("wifi_ap_channel", &wifi_ap_channel); + + /* AU does not allow channels above 13, although 14 works. */ + if (wifi_ap_channel > 13) { + wifi_ap_channel = 13; + } +#if 0 + /* US does not allow channels above 11, although they work. */ + if (wifi_ap_channel > 11) { + wifi_ap_channel = 11; + } +#endif + if (wifi_ap_channel < 1 || wifi_ap_channel > 14) { + wifi_ap_channel = 6; + } + + int8_t wifi_ap_authmode = AUTH_WPA_WPA2_PSK; + sysparam_get_int8("wifi_ap_authmode", &wifi_ap_authmode); + if (wifi_ap_authmode < AUTH_OPEN || wifi_ap_authmode > AUTH_MAX) + wifi_ap_authmode = AUTH_WPA_WPA2_PSK; + + int8_t wifi_ap_max_conn = 3; + sysparam_get_int8("wifi_ap_max_conn", &wifi_ap_max_conn); + if (wifi_ap_max_conn < 1 || wifi_ap_max_conn > 8) + wifi_ap_max_conn = 3; + + int32_t wifi_ap_beacon_interval = 100; + sysparam_get_int32("wifi_ap_beacon_interval", &wifi_ap_beacon_interval); + if (wifi_ap_beacon_interval < 0 || wifi_ap_beacon_interval > 1000) + wifi_ap_beacon_interval = 100; + + /* Default AP IP address and netmask. */ + char *wifi_ap_ip_addr = NULL; + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + if (!wifi_ap_ip_addr) { + sysparam_set_string("wifi_ap_ip_addr", "172.16.0.1"); + sysparam_get_string("wifi_ap_ip_addr", &wifi_ap_ip_addr); + } + char *wifi_ap_netmask = NULL; + sysparam_get_string("wifi_ap_netmask", &wifi_ap_netmask); + if (!wifi_ap_netmask) { + sysparam_set_string("wifi_ap_netmask", "255.255.0.0"); + sysparam_get_string("wifi_ap_netmask", &wifi_ap_netmask); + } + + if (strlen(wifi_ap_ip_addr) >= 7 && strlen(wifi_ap_netmask) >= 7) { + struct ip_info ap_ip; + ap_ip.ip.addr = ipaddr_addr(wifi_ap_ip_addr); + ap_ip.netmask.addr = ipaddr_addr(wifi_ap_netmask); + IP4_ADDR(&ap_ip.gw, 0, 0, 0, 0); + sdk_wifi_set_ip_info(1, &ap_ip); + + struct sdk_softap_config ap_config = { + .ssid_hidden = wifi_ap_ssid_hidden, + .channel = wifi_ap_channel, + .authmode = wifi_ap_authmode, + .max_connection = wifi_ap_max_conn, + .beacon_interval = wifi_ap_beacon_interval, + }; + strcpy((char *)ap_config.ssid, wifi_ap_ssid); + ap_config.ssid_len = strlen(wifi_ap_ssid); + strcpy((char *)ap_config.password, wifi_ap_password); + sdk_wifi_softap_set_config(&ap_config); + + int8_t wifi_ap_dhcp_leases = 4; + sysparam_get_int8("wifi_ap_dhcp_leases", &wifi_ap_dhcp_leases); + + if (wifi_ap_dhcp_leases) { + ip4_addr_t first_client_ip; + first_client_ip.addr = ap_ip.ip.addr + htonl(1); + + int8_t wifi_ap_dns = 1; + sysparam_get_int8("wifi_ap_dns", &wifi_ap_dns); + if (wifi_ap_dns < 0 || wifi_ap_dns > 1) + wifi_ap_dns = 1; + + dhcpserver_start(&first_client_ip, wifi_ap_dhcp_leases); + dhcpserver_set_router(&ap_ip.ip); + if (wifi_ap_dns) { + dhcpserver_set_dns(&ap_ip.ip); + xTaskCreate(dns_task, "WiFi Cfg DNS", 384, NULL, 2, NULL); + } + } + } + + free(wifi_ap_ip_addr); + free(wifi_ap_netmask); + } + + if (wifi_sta_ssid) free(wifi_sta_ssid); + if (wifi_sta_password) free(wifi_sta_password); + if (wifi_ap_ssid) free(wifi_ap_ssid); + if (wifi_ap_password) free(wifi_ap_password); + + server_params *params = malloc(sizeof(server_params)); + params->port = port; + params->wificfg_dispatch = wificfg_dispatch_list; + params->dispatch = dispatch; + + xTaskCreate(server_task, "WiFi Cfg HTTP", 464, params, 2, NULL); +} diff --git a/extras/wificfg/wificfg.h b/extras/wificfg/wificfg.h new file mode 100644 index 0000000..705b2f6 --- /dev/null +++ b/extras/wificfg/wificfg.h @@ -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__ diff --git a/extras/ws2812_i2s/ws2812_i2s.c b/extras/ws2812_i2s/ws2812_i2s.c index 310869b..712c894 100644 --- a/extras/ws2812_i2s/ws2812_i2s.c +++ b/extras/ws2812_i2s/ws2812_i2s.c @@ -60,7 +60,7 @@ volatile uint32_t dma_isr_counter = 0; 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()) { #ifdef WS2812_I2S_DEBUG @@ -145,7 +145,7 @@ void ws2812_i2s_init(uint32_t pixels_number) debug("i2s clock dividers, bclk=%d, clkm=%d\n", 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] = diff --git a/include/espressif/esp_wifi.h b/include/espressif/esp_wifi.h index 5d9ba19..8932974 100644 --- a/include/espressif/esp_wifi.h +++ b/include/espressif/esp_wifi.h @@ -44,9 +44,9 @@ enum { }; struct ip_info { - struct ip_addr ip; - struct ip_addr netmask; - struct ip_addr gw; + struct ip4_addr ip; + struct ip4_addr netmask; + struct ip4_addr gw; }; bool sdk_wifi_get_ip_info(uint8_t if_index, struct ip_info *info); diff --git a/include/espressif/sdk_private.h b/include/espressif/sdk_private.h index fa643a7..7ae4336 100644 --- a/include/espressif/sdk_private.h +++ b/include/espressif/sdk_private.h @@ -20,7 +20,7 @@ extern "C" { #endif -struct ip_addr; +struct ip4_addr; /********************************************* * Defined in libmain.a @@ -43,17 +43,6 @@ int sdk_uart_rx_one_char(char *buf); */ 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 } #endif diff --git a/include/espressif/spi_flash.h b/include/espressif/spi_flash.h index 61f8ae9..1c6a3b1 100644 --- a/include/espressif/spi_flash.h +++ b/include/espressif/spi_flash.h @@ -1,6 +1,6 @@ -/* +/* * copyright (c) Espressif System 2010 - * + * */ #ifndef __SPI_FLASH_H__ @@ -46,12 +46,6 @@ sdk_SpiFlashOpResult sdk_spi_flash_write(uint32_t des_addr, uint32_t *src, uint3 */ sdk_SpiFlashOpResult sdk_spi_flash_read(uint32_t src_addr, uint32_t *des, uint32_t size); -/* SDK uses this structure internally to account for flash size. - - See flashchip.h for more info. -*/ -extern sdk_flashchip_t sdk_flashchip; - #ifdef __cplusplus } #endif diff --git a/lib/allsymbols.rename b/lib/allsymbols.rename index 2d609bc..cf30bc9 100644 --- a/lib/allsymbols.rename +++ b/lib/allsymbols.rename @@ -289,6 +289,7 @@ os_timer_disarm sdk_os_timer_disarm os_timer_setfn sdk_os_timer_setfn os_update_cpu_frequency sdk_os_update_cpu_frequency pbkdf2_sha1 sdk_pbkdf2_sha1 +pbuf_alloc sdk_pbuf_alloc pbus_set_rxbbgain sdk_pbus_set_rxbbgain pend_flag_noise_check sdk_pend_flag_noise_check pend_flag_periodic_cal sdk_pend_flag_periodic_cal @@ -419,6 +420,7 @@ ram_set_txbb_atten sdk_ram_set_txbb_atten ram_start_noisefloor sdk_ram_start_noisefloor ram_tx_mac_disable sdk_ram_tx_mac_disable ram_tx_mac_enable sdk_ram_tx_mac_enable +rand hwrand rc4_skip sdk_rc4_skip rcAttach sdk_rcAttach rc_cal sdk_rc_cal diff --git a/lib/libgcc.a b/lib/libgcc.a new file mode 100644 index 0000000..b981970 Binary files /dev/null and b/lib/libgcc.a differ diff --git a/lib/libgcc.remove b/lib/libgcc.remove new file mode 100644 index 0000000..f573074 --- /dev/null +++ b/lib/libgcc.remove @@ -0,0 +1,24 @@ +# Object files to be removed from libgcc +# These are provided by the ROM. +_addsubdf3.o +_addsubsf3.o +_divdf3.o +_divdi3.o +_divsi3.o +_extendsfdf2.o +_fixdfsi.o +_fixunssfsi.o +_floatsidf.o +_floatsisf.o +_floatunsidf.o +_floatunsisf.o +_muldf3.o +_muldi3.o +_mulsf3.o +_subdf3.o +_subsf3.o +_truncdfsf2.o +_udivdi3.o +_umoddi3.o +_umodsi3.o +_umulsidi3.o diff --git a/lib/libmain.a b/lib/libmain.a index 60657ec..cd6f83a 100644 Binary files a/lib/libmain.a and b/lib/libmain.a differ diff --git a/lib/libmain.remove b/lib/libmain.remove index 35145b3..158fba7 100644 --- a/lib/libmain.remove +++ b/lib/libmain.remove @@ -3,3 +3,4 @@ printf-stdarg.o libc.o xtensa_vectors.o app_main.o +ets_timer.o diff --git a/lib/libnet80211.a b/lib/libnet80211.a index 4a36331..1146020 100644 Binary files a/lib/libnet80211.a and b/lib/libnet80211.a differ diff --git a/lib/libpp.a b/lib/libpp.a index 2747863..39631a2 100644 Binary files a/lib/libpp.a and b/lib/libpp.a differ diff --git a/lib/libwpa.a b/lib/libwpa.a index a8fa39a..1c99007 100644 Binary files a/lib/libwpa.a and b/lib/libwpa.a differ diff --git a/libc/README.md b/libc/README.md index 0a2941d..f4d8199 100644 --- a/libc/README.md +++ b/libc/README.md @@ -1,3 +1 @@ -Newlib 2.2.0 with xtensa & locking patches, built from commit daa6ae40cdc8099f54c3e68a586fc1b906169c5a - -For details on newlib in esp-open-rtos, see https://github.com/SuperHouse/esp-open-rtos/wiki/libc-configuration +Newlib from git://sourceware.org/git/newlib-cygwin.git with xtensa & locking patches see https://github.com/ourairquality/newlib and built from commit 7bcbbff5f7e3600806f352e88ec23ae0300edc29 diff --git a/libc/libc.remove b/libc/libc.remove new file mode 100644 index 0000000..ddf65ba --- /dev/null +++ b/libc/libc.remove @@ -0,0 +1,13 @@ +# Object files to remove from libc.a +# These are provided by the ROM. +lib_a-bzero.o +lib_a-memcmp.o +lib_a-memcpy.o +lib_a-memmove.o +lib_a-memset.o +lib_a-strcmp.o +lib_a-strcpy.o +lib_a-strlen.o +lib_a-strncmp.o +lib_a-strncpy.o +lib_a-strstr.o diff --git a/libc/share/info/configure.info b/libc/share/info/configure.info deleted file mode 100644 index eccae2a..0000000 --- a/libc/share/info/configure.info +++ /dev/null @@ -1,2721 +0,0 @@ -This is configure.info, produced by makeinfo version 6.0 from -configure.texi. - -INFO-DIR-SECTION GNU admin -START-INFO-DIR-ENTRY -* configure: (configure). The GNU configure and build system -END-INFO-DIR-ENTRY - -This file documents the GNU configure and build system. - - Copyright (C) 1998 Cygnus Solutions. - - Permission is granted to make and distribute verbatim copies of this -manual provided the copyright notice and this permission notice are -preserved on all copies. - - Permission is granted to copy and distribute modified versions of -this manual under the conditions for verbatim copying, provided that the -entire resulting derived work is distributed under the terms of a -permission notice identical to this one. - - Permission is granted to copy and distribute translations of this -manual into another language, under the above conditions for modified -versions, except that this permission notice may be stated in a -translation approved by the Foundation. - - -File: configure.info, Node: Top, Next: Introduction, Up: (dir) - -GNU configure and build system -****************************** - -The GNU configure and build system. - -* Menu: - -* Introduction:: Introduction. -* Getting Started:: Getting Started. -* Files:: Files. -* Configuration Names:: Configuration Names. -* Cross Compilation Tools:: Cross Compilation Tools. -* Canadian Cross:: Canadian Cross. -* Cygnus Configure:: Cygnus Configure. -* Multilibs:: Multilibs. -* FAQ:: Frequently Asked Questions. -* Index:: Index. - - -File: configure.info, Node: Introduction, Next: Getting Started, Prev: Top, Up: Top - -1 Introduction -************** - -This document describes the GNU configure and build systems. It -describes how autoconf, automake, libtool, and make fit together. It -also includes a discussion of the older Cygnus configure system. - - This document does not describe in detail how to use each of the -tools; see the respective manuals for that. Instead, it describes which -files the developer must write, which files are machine generated and -how they are generated, and where certain common problems should be -addressed. - - This document draws on several sources, including the autoconf manual -by David MacKenzie (*note autoconf overview: (autoconf)Top.), the -automake manual by David MacKenzie and Tom Tromey (*note automake -overview: (automake)Top.), the libtool manual by Gordon Matzigkeit -(*note libtool overview: (libtool)Top.), and the Cygnus configure manual -by K. Richard Pixley. - -* Menu: - -* Goals:: Goals. -* Tools:: The tools. -* History:: History. -* Building:: Building. - - -File: configure.info, Node: Goals, Next: Tools, Up: Introduction - -1.1 Goals -========= - -The GNU configure and build system has two main goals. - - The first is to simplify the development of portable programs. The -system permits the developer to concentrate on writing the program, -simplifying many details of portability across Unix and even Windows -systems, and permitting the developer to describe how to build the -program using simple rules rather than complex Makefiles. - - The second is to simplify the building of programs distributed as -source code. All programs are built using a simple, standardized, two -step process. The program builder need not install any special tools in -order to build the program. - - -File: configure.info, Node: Tools, Next: History, Prev: Goals, Up: Introduction - -1.2 Tools -========= - -The GNU configure and build system is comprised of several different -tools. Program developers must build and install all of these tools. - - People who just want to build programs from distributed sources -normally do not need any special tools beyond a Unix shell, a make -program, and a C compiler. - -autoconf - provides a general portability framework, based on testing the - features of the host system at build time. -automake - a system for describing how to build a program, permitting the - developer to write a simplified 'Makefile'. -libtool - a standardized approach to building shared libraries. -gettext - provides a framework for translation of text messages into other - languages; not really discussed in this document. -m4 - autoconf requires the GNU version of m4; the standard Unix m4 does - not suffice. -perl - automake requires perl. - - -File: configure.info, Node: History, Next: Building, Prev: Tools, Up: Introduction - -1.3 History -=========== - -This is a very brief and probably inaccurate history. - - As the number of Unix variants increased during the 1980s, it became -harder to write programs which could run on all variants. While it was -often possible to use '#ifdef' to identify particular systems, -developers frequently did not have access to every system, and the -characteristics of some systems changed from version to version. - - By 1992, at least three different approaches had been developed: - * The Metaconfig program, by Larry Wall, Harlan Stenn, and Raphael - Manfredi. - * The Cygnus configure script, by K. Richard Pixley, and the gcc - configure script, by Richard Stallman. These use essentially the - same approach, and the developers communicated regularly. - * The autoconf program, by David MacKenzie. - - The Metaconfig program is still used for Perl and a few other -programs. It is part of the Dist package. I do not know if it is being -developed. - - In 1994, David MacKenzie and others modified autoconf to incorporate -all the features of Cygnus configure. Since then, there has been a slow -but steady conversion of GNU programs from Cygnus configure to autoconf. -gcc has been converted, eliminating the gcc configure script. - - GNU autoconf was regularly maintained until late 1996. As of this -writing in June, 1998, it has no public maintainer. - - Most programs are built using the make program, which requires the -developer to write Makefiles describing how to build the programs. -Since most programs are built in pretty much the same way, this led to a -lot of duplication. - - The X Window system is built using the imake tool, which uses a -database of rules to eliminate the duplication. However, building a -tool which was developed using imake requires that the builder have -imake installed, violating one of the goals of the GNU system. - - The new BSD make provides a standard library of Makefile fragments, -which permits developers to write very simple Makefiles. However, this -requires that the builder install the new BSD make program. - - In 1994, David MacKenzie wrote the first version of automake, which -permitted writing a simple build description which was converted into a -Makefile which could be used by the standard make program. In 1995, Tom -Tromey completely rewrote automake in Perl, and he continues to enhance -it. - - Various free packages built libraries, and by around 1995 several -included support to build shared libraries on various platforms. -However, there was no consistent approach. In early 1996, Gordon -Matzigkeit began working on libtool, which provided a standardized -approach to building shared libraries. This was integrated into -automake from the start. - - The development of automake and libtool was driven by the GNITS -project, a group of GNU maintainers who designed standardized tools to -help meet the GNU coding standards. - - -File: configure.info, Node: Building, Prev: History, Up: Introduction - -1.4 Building -============ - -Most readers of this document should already know how to build a tool by -running 'configure' and 'make'. This section may serve as a quick -introduction or reminder. - - Building a tool is normally as simple as running 'configure' followed -by 'make'. You should normally run 'configure' from an empty directory, -using some path to refer to the 'configure' script in the source -directory. The directory in which you run 'configure' is called the -"object directory". - - In order to use a object directory which is different from the source -directory, you must be using the GNU version of 'make', which has the -required 'VPATH' support. Despite this restriction, using a different -object directory is highly recommended: - * It keeps the files generated during the build from cluttering up - your sources. - * It permits you to remove the built files by simply removing the - entire build directory. - * It permits you to build from the same sources with several sets of - configure options simultaneously. - - If you don't have GNU 'make', you will have to run 'configure' in the -source directory. All GNU packages should support this; in particular, -GNU packages should not assume the presence of GNU 'make'. - - After running 'configure', you can build the tools by running 'make'. - - To install the tools, run 'make install'. Installing the tools will -copy the programs and any required support files to the "installation -directory". The location of the installation directory is controlled by -'configure' options, as described below. - - In the Cygnus tree at present, the info files are built and installed -as a separate step. To build them, run 'make info'. To install them, -run 'make install-info'. The equivalent html files are also built and -installed in a separate step. To build the html files, run 'make html'. -To install the html files run 'make install-html'. - - All 'configure' scripts support a wide variety of options. The most -interesting ones are '--with' and '--enable' options which are generally -specific to particular tools. You can usually use the '--help' option -to get a list of interesting options for a particular configure script. - - The only generic options you are likely to use are the '--prefix' and -'--exec-prefix' options. These options are used to specify the -installation directory. - - The directory named by the '--prefix' option will hold machine -independent files such as info files. - - The directory named by the '--exec-prefix' option, which is normally -a subdirectory of the '--prefix' directory, will hold machine dependent -files such as executables. - - The default for '--prefix' is '/usr/local'. The default for -'--exec-prefix' is the value used for '--prefix'. - - The convention used in Cygnus releases is to use a '--prefix' option -of '/usr/cygnus/RELEASE', where RELEASE is the name of the release, and -to use a '--exec-prefix' option of '/usr/cygnus/RELEASE/H-HOST', where -HOST is the configuration name of the host system (*note Configuration -Names::). - - Do not use either the source or the object directory as the -installation directory. That will just lead to confusion. - - -File: configure.info, Node: Getting Started, Next: Files, Prev: Introduction, Up: Top - -2 Getting Started -***************** - -To start using the GNU configure and build system with your software -package, you must write three files, and you must run some tools to -manually generate additional files. - -* Menu: - -* Write configure.in:: Write configure.in. -* Write Makefile.am:: Write Makefile.am. -* Write acconfig.h:: Write acconfig.h. -* Generate files:: Generate files. -* Getting Started Example:: Example. - - -File: configure.info, Node: Write configure.in, Next: Write Makefile.am, Up: Getting Started - -2.1 Write configure.in -====================== - -You must first write the file 'configure.in'. This is an autoconf input -file, and the autoconf manual describes in detail what this file should -look like. - - You will write tests in your 'configure.in' file to check for -conditions that may change from one system to another, such as the -presence of particular header files or functions. - - For example, not all systems support the 'gettimeofday' function. If -you want to use the 'gettimeofday' function when it is available, and to -use some other function when it is not, you would check for this by -putting 'AC_CHECK_FUNCS(gettimeofday)' in 'configure.in'. - - When the configure script is run at build time, this will arrange to -define the preprocessor macro 'HAVE_GETTIMEOFDAY' to the value 1 if the -'gettimeofday' function is available, and to not define the macro at all -if the function is not available. Your code can then use '#ifdef' to -test whether it is safe to call 'gettimeofday'. - - If you have an existing body of code, the 'autoscan' program may help -identify potential portability problems, and hence configure tests that -you will want to use. *Note (autoconf)Invoking autoscan::. - - Another handy tool for an existing body of code is 'ifnames'. This -will show you all the preprocessor conditionals that the code already -uses. *Note (autoconf)Invoking ifnames::. - - Besides the portability tests which are specific to your particular -package, every 'configure.in' file should contain the following macros. - -'AC_INIT' - This macro takes a single argument, which is the name of a file in - your package. For example, 'AC_INIT(foo.c)'. - -'AC_PREREQ(VERSION)' - This macro is optional. It may be used to indicate the version of - 'autoconf' that you are using. This will prevent users from - running an earlier version of 'autoconf' and perhaps getting an - invalid 'configure' script. For example, 'AC_PREREQ(2.12)'. - -'AM_INIT_AUTOMAKE' - This macro takes two arguments: the name of the package, and a - version number. For example, 'AM_INIT_AUTOMAKE(foo, 1.0)'. (This - macro is not needed if you are not using automake). - -'AM_CONFIG_HEADER' - This macro names the header file which will hold the preprocessor - macro definitions at run time. Normally this should be 'config.h'. - Your sources would then use '#include "config.h"' to include it. - - This macro may optionally name the input file for that header file; - by default, this is 'config.h.in', but that file name works poorly - on DOS filesystems. Therefore, it is often better to name it - explicitly as 'config.in'. - - This is what you should normally put in 'configure.in': - AM_CONFIG_HEADER(config.h:config.in) - - (If you are not using automake, use 'AC_CONFIG_HEADER' rather than - 'AM_CONFIG_HEADER'). - -'AM_MAINTAINER_MODE' - This macro always appears in Cygnus configure scripts. Other - programs may or may not use it. - - If this macro is used, the '--enable-maintainer-mode' option is - required to enable automatic rebuilding of generated files used by - the configure system. This of course requires that developers be - aware of, and use, that option. - - If this macro is not used, then the generated files will always be - rebuilt automatically. This will cause problems if the wrong - versions of autoconf, automake, or others are in the builder's - 'PATH'. - - (If you are not using automake, you do not need to use this macro). - -'AC_EXEEXT' - Either this macro or 'AM_EXEEXT' always appears in Cygnus configure - files. Other programs may or may not use one of them. - - This macro looks for the executable suffix used on the host system. - On Unix systems, this is the empty string. On Windows systems, - this is '.exe'. This macro directs automake to use the executable - suffix as appropriate when creating programs. This macro does not - take any arguments. - - The 'AC_EXEEXT' form is new, and is part of a Cygnus patch to - autoconf to support compiling with Visual C++. Older programs use - 'AM_EXEEXT' instead. - - (Programs which do not use automake use neither 'AC_EXEEXT' nor - 'AM_EXEEXT'). - -'AC_PROG_CC' - If you are writing C code, you will normally want to use this - macro. It locates the C compiler to use. It does not take any - arguments. - - However, if this 'configure.in' file is for a library which is to - be compiled by a cross compiler which may not fully work, then you - will not want to use 'AC_PROG_CC'. Instead, you will want to use a - variant which does not call the macro 'AC_PROG_CC_WORKS'. Examples - can be found in various 'configure.in' files for libraries that are - compiled with cross compilers, such as libiberty or libgloss. This - is essentially a bug in autoconf, and there will probably be a - better workaround at some point. - -'AC_PROG_CXX' - If you are writing C++ code, you will want to use this macro. It - locates the C++ compiler to use. It does not take any arguments. - The same cross compiler comments apply as for 'AC_PROG_CC'. - -'AM_PROG_LIBTOOL' - If you want to build libraries, and you want to permit them to be - shared, or you want to link against libraries which were built - using libtool, then you will need this macro. This macro is - required in order to use libtool. - - By default, this will cause all libraries to be built as shared - libraries. To prevent this-to change the default-use - 'AM_DISABLE_SHARED' before 'AM_PROG_LIBTOOL'. The configure - options '--enable-shared' and '--disable-shared' may be used to - override the default at build time. - -'AC_DEFINE(_GNU_SOURCE)' - GNU packages should normally include this line before any other - feature tests. This defines the macro '_GNU_SOURCE' when - compiling, which directs the libc header files to provide the - standard GNU system interfaces including all GNU extensions. If - this macro is not defined, certain GNU extensions may not be - available. - -'AC_OUTPUT' - This macro takes a list of file names which the configure process - should produce. This is normally a list of one or more 'Makefile' - files in different directories. If your package lives entirely in - a single directory, you would use simply 'AC_OUTPUT(Makefile)'. If - you also have, for example, a 'lib' subdirectory, you would use - 'AC_OUTPUT(Makefile lib/Makefile)'. - - If you want to use locally defined macros in your 'configure.in' -file, then you will need to write a 'acinclude.m4' file which defines -them (if not using automake, this file is called 'aclocal.m4'). -Alternatively, you can put separate macros in an 'm4' subdirectory, and -put 'ACLOCAL_AMFLAGS = -I m4' in your 'Makefile.am' file so that the -'aclocal' program will be able to find them. - - The different macro prefixes indicate which tool defines the macro. -Macros which start with 'AC_' are part of autoconf. Macros which start -with 'AM_' are provided by automake or libtool. - - -File: configure.info, Node: Write Makefile.am, Next: Write acconfig.h, Prev: Write configure.in, Up: Getting Started - -2.2 Write Makefile.am -===================== - -You must write the file 'Makefile.am'. This is an automake input file, -and the automake manual describes in detail what this file should look -like. - - The automake commands in 'Makefile.am' mostly look like variable -assignments in a 'Makefile'. automake recognizes special variable -names, and automatically add make rules to the output as needed. - - There will be one 'Makefile.am' file for each directory in your -package. For each directory with subdirectories, the 'Makefile.am' file -should contain the line - SUBDIRS = DIR DIR ... -where each DIR is the name of a subdirectory. - - For each 'Makefile.am', there should be a corresponding 'Makefile' in -the 'AC_OUTPUT' macro in 'configure.in'. - - Every 'Makefile.am' written at Cygnus should contain the line - AUTOMAKE_OPTIONS = cygnus -This puts automake into Cygnus mode. See the automake manual for -details. - - You may to include the version number of 'automake' that you are -using on the 'AUTOMAKE_OPTIONS' line. For example, - AUTOMAKE_OPTIONS = cygnus 1.3 -This will prevent users from running an earlier version of 'automake' -and perhaps getting an invalid 'Makefile.in'. - - If your package builds a program, then in the directory where that -program is built you will normally want a line like - bin_PROGRAMS = PROGRAM -where PROGRAM is the name of the program. You will then want a line -like - PROGRAM_SOURCES = FILE FILE ... -where each FILE is the name of a source file to link into the program -(e.g., 'foo.c'). - - If your package builds a library, and you do not want the library to -ever be built as a shared library, then in the directory where that -library is built you will normally want a line like - lib_LIBRARIES = libNAME.a -where 'libNAME.a' is the name of the library. You will then want a line -like - libNAME_a_SOURCES = FILE FILE ... -where each FILE is the name of a source file to add to the library. - - If your package builds a library, and you want to permit building the -library as a shared library, then in the directory where that library is -built you will normally want a line like - lib_LTLIBRARIES = libNAME.la - The use of 'LTLIBRARIES', and the '.la' extension, indicate a library -to be built using libtool. As usual, you will then want a line like - libNAME_la_SOURCES = FILE FILE ... - - The strings 'bin' and 'lib' that appear above in 'bin_PROGRAMS' and -'lib_LIBRARIES' are not arbitrary. They refer to particular -directories, which may be set by the '--bindir' and '--libdir' options -to 'configure'. If those options are not used, the default values are -based on the '--prefix' or '--exec-prefix' options to 'configure'. It -is possible to use other names if the program or library should be -installed in some other directory. - - The 'Makefile.am' file may also contain almost anything that may -appear in a normal 'Makefile'. automake also supports many other -special variables, as well as conditionals. - - See the automake manual for more information. - - -File: configure.info, Node: Write acconfig.h, Next: Generate files, Prev: Write Makefile.am, Up: Getting Started - -2.3 Write acconfig.h -==================== - -If you are generating a portability header file, (i.e., you are using -'AM_CONFIG_HEADER' in 'configure.in'), then you will have to write a -'acconfig.h' file. It will have to contain the following lines. - - /* Name of package. */ - #undef PACKAGE - - /* Version of package. */ - #undef VERSION - - This requirement is really a bug in the system, and the requirement -may be eliminated at some later date. - - The 'acconfig.h' file will also similar comment and '#undef' lines -for any unusual macros in the 'configure.in' file, including any macro -which appears in a 'AC_DEFINE' macro. - - In particular, if you are writing a GNU package and therefore include -'AC_DEFINE(_GNU_SOURCE)' in 'configure.in' as suggested above, you will -need lines like this in 'acconfig.h': - /* Enable GNU extensions. */ - #undef _GNU_SOURCE - - Normally the 'autoheader' program will inform you of any such -requirements by printing an error message when it is run. However, if -you do anything particular odd in your 'configure.in' file, you will -have to make sure that the right entries appear in 'acconfig.h', since -otherwise the results of the tests may not be available in the -'config.h' file which your code will use. - - (Thee 'PACKAGE' and 'VERSION' lines are not required if you are not -using automake, and in that case you may not need a 'acconfig.h' file at -all). - - -File: configure.info, Node: Generate files, Next: Getting Started Example, Prev: Write acconfig.h, Up: Getting Started - -2.4 Generate files -================== - -Once you have written 'configure.in', 'Makefile.am', 'acconfig.h', and -possibly 'acinclude.m4', you must use autoconf and automake programs to -produce the first versions of the generated files. This is done by -executing the following sequence of commands. - - aclocal - autoconf - autoheader - automake - - The 'aclocal' and 'automake' commands are part of the automake -package, and the 'autoconf' and 'autoheader' commands are part of the -autoconf package. - - If you are using a 'm4' subdirectory for your macros, you will need -to use the '-I m4' option when you run 'aclocal'. - - If you are not using the Cygnus tree, use the '-a' option when -running 'automake' command in order to copy the required support files -into your source directory. - - If you are using libtool, you must build and install the libtool -package with the same '--prefix' and '--exec-prefix' options as you used -with the autoconf and automake packages. You must do this before -running any of the above commands. If you are not using the Cygnus -tree, you will need to run the 'libtoolize' program to copy the libtool -support files into your directory. - - Once you have managed to run these commands without getting any -errors, you should create a new empty directory, and run the 'configure' -script which will have been created by 'autoconf' with the -'--enable-maintainer-mode' option. This will give you a set of -Makefiles which will include rules to automatically rebuild all the -generated files. - - After doing that, whenever you have changed some of the input files -and want to regenerated the other files, go to your object directory and -run 'make'. Doing this is more reliable than trying to rebuild the -files manually, because there are complex order dependencies and it is -easy to forget something. - - -File: configure.info, Node: Getting Started Example, Prev: Generate files, Up: Getting Started - -2.5 Example -=========== - -Let's consider a trivial example. - - Suppose we want to write a simple version of 'touch'. Our program, -which we will call 'poke', will take a single file name argument, and -use the 'utime' system call to set the modification and access times of -the file to the current time. We want this program to be highly -portable. - - We'll first see what this looks like without using autoconf and -automake, and then see what it looks like with them. - -* Menu: - -* Getting Started Example 1:: First Try. -* Getting Started Example 2:: Second Try. -* Getting Started Example 3:: Third Try. -* Generate Files in Example:: Generate Files. - - -File: configure.info, Node: Getting Started Example 1, Next: Getting Started Example 2, Up: Getting Started Example - -2.5.1 First Try ---------------- - -Here is our first try at 'poke.c'. Note that we've written it without -ANSI/ISO C prototypes, since we want it to be highly portable. - - #include - #include - #include - #include - - int - main (argc, argv) - int argc; - char **argv; - { - if (argc != 2) - { - fprintf (stderr, "Usage: poke file\n"); - exit (1); - } - - if (utime (argv[1], NULL) < 0) - { - perror ("utime"); - exit (1); - } - - exit (0); - } - - We also write a simple 'Makefile'. - - CC = gcc - CFLAGS = -g -O2 - - all: poke - - poke: poke.o - $(CC) -o poke $(CFLAGS) $(LDFLAGS) poke.o - - So far, so good. - - Unfortunately, there are a few problems. - - On older Unix systems derived from BSD 4.3, the 'utime' system call -does not accept a second argument of 'NULL'. On those systems, we need -to pass a pointer to 'struct utimbuf' structure. Unfortunately, even -older systems don't define that structure; on those systems, we need to -pass an array of two 'long' values. - - The header file 'stdlib.h' was invented by ANSI C, and older systems -don't have a copy. We included it above to get a declaration of 'exit'. - - We can find some of these portability problems by running 'autoscan', -which will create a 'configure.scan' file which we can use as a -prototype for our 'configure.in' file. I won't show the output, but it -will notice the potential problems with 'utime' and 'stdlib.h'. - - In our 'Makefile', we don't provide any way to install the program. -This doesn't matter much for such a simple example, but a real program -will need an 'install' target. For that matter, we will also want a -'clean' target. - - -File: configure.info, Node: Getting Started Example 2, Next: Getting Started Example 3, Prev: Getting Started Example 1, Up: Getting Started Example - -2.5.2 Second Try ----------------- - -Here is our second try at this program. - - We modify 'poke.c' to use preprocessor macros to control what -features are available. (I've cheated a bit by using the same macro -names which autoconf will use). - - #include - - #ifdef STDC_HEADERS - #include - #endif - - #include - - #ifdef HAVE_UTIME_H - #include - #endif - - #ifndef HAVE_UTIME_NULL - - #include - - #ifndef HAVE_STRUCT_UTIMBUF - - struct utimbuf - { - long actime; - long modtime; - }; - - #endif - - static int - utime_now (file) - char *file; - { - struct utimbuf now; - - now.actime = now.modtime = time (NULL); - return utime (file, &now); - } - - #define utime(f, p) utime_now (f) - - #endif /* HAVE_UTIME_NULL */ - - int - main (argc, argv) - int argc; - char **argv; - { - if (argc != 2) - { - fprintf (stderr, "Usage: poke file\n"); - exit (1); - } - - if (utime (argv[1], NULL) < 0) - { - perror ("utime"); - exit (1); - } - - exit (0); - } - - Here is the associated 'Makefile'. We've added support for the -preprocessor flags we use. We've also added 'install' and 'clean' -targets. - - # Set this to your installation directory. - bindir = /usr/local/bin - - # Uncomment this if you have the standard ANSI/ISO C header files. - # STDC_HDRS = -DSTDC_HEADERS - - # Uncomment this if you have utime.h. - # UTIME_H = -DHAVE_UTIME_H - - # Uncomment this if utime (FILE, NULL) works on your system. - # UTIME_NULL = -DHAVE_UTIME_NULL - - # Uncomment this if struct utimbuf is defined in utime.h. - # UTIMBUF = -DHAVE_STRUCT_UTIMBUF - - CC = gcc - CFLAGS = -g -O2 - - ALL_CFLAGS = $(STDC_HDRS) $(UTIME_H) $(UTIME_NULL) $(UTIMBUF) $(CFLAGS) - - all: poke - - poke: poke.o - $(CC) -o poke $(ALL_CFLAGS) $(LDFLAGS) poke.o - - .c.o: - $(CC) -c $(ALL_CFLAGS) poke.c - - install: poke - cp poke $(bindir)/poke - - clean: - rm poke poke.o - - Some problems with this approach should be clear. - - Users who want to compile poke will have to know how 'utime' works on -their systems, so that they can uncomment the 'Makefile' correctly. - - The installation is done using 'cp', but many systems have an -'install' program which may be used, and which supports optional -features such as stripping debugging information out of the installed -binary. - - The use of 'Makefile' variables like 'CC', 'CFLAGS' and 'LDFLAGS' -follows the requirements of the GNU standards. This is convenient for -all packages, since it reduces surprises for users. However, it is easy -to get the details wrong, and wind up with a slightly nonstandard -distribution. - - -File: configure.info, Node: Getting Started Example 3, Next: Generate Files in Example, Prev: Getting Started Example 2, Up: Getting Started Example - -2.5.3 Third Try ---------------- - -For our third try at this program, we will write a 'configure.in' script -to discover the configuration features on the host system, rather than -requiring the user to edit the 'Makefile'. We will also write a -'Makefile.am' rather than a 'Makefile'. - - The only change to 'poke.c' is to add a line at the start of the -file: - #include "config.h" - - The new 'configure.in' file is as follows. - - AC_INIT(poke.c) - AM_INIT_AUTOMAKE(poke, 1.0) - AM_CONFIG_HEADER(config.h:config.in) - AC_PROG_CC - AC_HEADER_STDC - AC_CHECK_HEADERS(utime.h) - AC_EGREP_HEADER(utimbuf, utime.h, AC_DEFINE(HAVE_STRUCT_UTIMBUF)) - AC_FUNC_UTIME_NULL - AC_OUTPUT(Makefile) - - The first four macros in this file, and the last one, were described -above; see *note Write configure.in::. If we omit these macros, then -when we run 'automake' we will get a reminder that we need them. - - The other macros are standard autoconf macros. - -'AC_HEADER_STDC' - Check for standard C headers. -'AC_CHECK_HEADERS' - Check whether a particular header file exists. -'AC_EGREP_HEADER' - Check for a particular string in a particular header file, in this - case checking for 'utimbuf' in 'utime.h'. -'AC_FUNC_UTIME_NULL' - Check whether 'utime' accepts a NULL second argument to set the - file change time to the current time. - - See the autoconf manual for a more complete description. - - The new 'Makefile.am' file is as follows. Note how simple this is -compared to our earlier 'Makefile'. - - bin_PROGRAMS = poke - - poke_SOURCES = poke.c - - This means that we should build a single program name 'poke'. It -should be installed in the binary directory, which we called 'bindir' -earlier. The program 'poke' is built from the source file 'poke.c'. - - We must also write a 'acconfig.h' file. Besides 'PACKAGE' and -'VERSION', which must be mentioned for all packages which use automake, -we must include 'HAVE_STRUCT_UTIMBUF', since we mentioned it in an -'AC_DEFINE'. - - /* Name of package. */ - #undef PACKAGE - - /* Version of package. */ - #undef VERSION - - /* Whether utime.h defines struct utimbuf. */ - #undef HAVE_STRUCT_UTIMBUF - - -File: configure.info, Node: Generate Files in Example, Prev: Getting Started Example 3, Up: Getting Started Example - -2.5.4 Generate Files --------------------- - -We must now generate the other files, using the following commands. - - aclocal - autoconf - autoheader - automake - - When we run 'autoheader', it will remind us of any macros we forgot -to add to 'acconfig.h'. - - When we run 'automake', it will want to add some files to our -distribution. It will add them automatically if we use the -'--add-missing' option. - - By default, 'automake' will run in GNU mode, which means that it will -want us to create certain additional files; as of this writing, it will -want 'NEWS', 'README', 'AUTHORS', and 'ChangeLog', all of which are -files which should appear in a standard GNU distribution. We can either -add those files, or run 'automake' with the '--foreign' option. - - Running these tools will generate the following files, all of which -are described in the next chapter. - - * 'aclocal.m4' - * 'configure' - * 'config.in' - * 'Makefile.in' - * 'stamp-h.in' - - -File: configure.info, Node: Files, Next: Configuration Names, Prev: Getting Started, Up: Top - -3 Files -******* - -As was seen in the previous chapter, the GNU configure and build system -uses a number of different files. The developer must write a few files. -The others are generated by various tools. - - The system is rather flexible, and can be used in many different -ways. In describing the files that it uses, I will describe the common -case, and mention some other cases that may arise. - -* Menu: - -* Developer Files:: Developer Files. -* Build Files:: Build Files. -* Support Files:: Support Files. - - -File: configure.info, Node: Developer Files, Next: Build Files, Up: Files - -3.1 Developer Files -=================== - -This section describes the files written or generated by the developer -of a package. - -* Menu: - -* Developer Files Picture:: Developer Files Picture. -* Written Developer Files:: Written Developer Files. -* Generated Developer Files:: Generated Developer Files. - - -File: configure.info, Node: Developer Files Picture, Next: Written Developer Files, Up: Developer Files - -3.1.1 Developer Files Picture ------------------------------ - -Here is a picture of the files which are written by the developer, the -generated files which would be included with a complete source -distribution, and the tools which create those files. The file names -are plain text and the tool names are enclosed by '*' characters (e.g., -'autoheader' is the name of a tool, not the name of a file). - - acconfig.h configure.in Makefile.am - | | | - | --------------+---------------------- | - | | | | | - v v | acinclude.m4 | | - *autoheader* | | v v - | | v --->*automake* - v |--->*aclocal* | | - config.in | | | v - | v | Makefile.in - | aclocal.m4--- - | | - v v - *autoconf* - | - v - configure - -File: configure.info, Node: Written Developer Files, Next: Generated Developer Files, Prev: Developer Files Picture, Up: Developer Files - -3.1.2 Written Developer Files ------------------------------ - -The following files would be written by the developer. - -'configure.in' - This is the configuration script. This script contains invocations - of autoconf macros. It may also contain ordinary shell script - code. This file will contain feature tests for portability issues. - The last thing in the file will normally be an 'AC_OUTPUT' macro - listing which files to create when the builder runs the configure - script. This file is always required when using the GNU configure - system. *Note Write configure.in::. - -'Makefile.am' - This is the automake input file. It describes how the code should - be built. It consists of definitions of automake variables. It - may also contain ordinary Makefile targets. This file is only - needed when using automake (newer tools normally use automake, but - there are still older tools which have not been converted, in which - the developer writes 'Makefile.in' directly). *Note Write - Makefile.am::. - -'acconfig.h' - When the configure script creates a portability header file, by - using 'AM_CONFIG_HEADER' (or, if not using automake, - 'AC_CONFIG_HEADER'), this file is used to describe macros which are - not recognized by the 'autoheader' command. This is normally a - fairly uninteresting file, consisting of a collection of '#undef' - lines with comments. Normally any call to 'AC_DEFINE' in - 'configure.in' will require a line in this file. *Note Write - acconfig.h::. - -'acinclude.m4' - This file is not always required. It defines local autoconf - macros. These macros may then be used in 'configure.in'. If you - don't need any local autoconf macros, then you don't need this file - at all. In fact, in general, you never need local autoconf macros, - since you can put everything in 'configure.in', but sometimes a - local macro is convenient. - - Newer tools may omit 'acinclude.m4', and instead use a - subdirectory, typically named 'm4', and define 'ACLOCAL_AMFLAGS = - -I m4' in 'Makefile.am' to force 'aclocal' to look there for macro - definitions. The macro definitions are then placed in separate - files in that directory. - - The 'acinclude.m4' file is only used when using automake; in older - tools, the developer writes 'aclocal.m4' directly, if it is needed. - - -File: configure.info, Node: Generated Developer Files, Prev: Written Developer Files, Up: Developer Files - -3.1.3 Generated Developer Files -------------------------------- - -The following files would be generated by the developer. - - When using automake, these files are normally not generated manually -after the first time. Instead, the generated 'Makefile' contains rules -to automatically rebuild the files as required. When -'AM_MAINTAINER_MODE' is used in 'configure.in' (the normal case in -Cygnus code), the automatic rebuilding rules will only be defined if you -configure using the '--enable-maintainer-mode' option. - - When using automatic rebuilding, it is important to ensure that all -the various tools have been built and installed on your 'PATH'. Using -automatic rebuilding is highly recommended, so much so that I'm not -going to explain what you have to do if you don't use it. - -'configure' - This is the configure script which will be run when building the - package. This is generated by 'autoconf' from 'configure.in' and - 'aclocal.m4'. This is a shell script. - -'Makefile.in' - This is the file which the configure script will turn into the - 'Makefile' at build time. This file is generated by 'automake' - from 'Makefile.am'. If you aren't using automake, you must write - this file yourself. This file is pretty much a normal 'Makefile', - with some configure substitutions for certain variables. - -'aclocal.m4' - This file is created by the 'aclocal' program, based on the - contents of 'configure.in' and 'acinclude.m4' (or, as noted in the - description of 'acinclude.m4' above, on the contents of an 'm4' - subdirectory). This file contains definitions of autoconf macros - which 'autoconf' will use when generating the file 'configure'. - These autoconf macros may be defined by you in 'acinclude.m4' or - they may be defined by other packages such as automake, libtool or - gettext. If you aren't using automake, you will normally write - this file yourself; in that case, if 'configure.in' uses only - standard autoconf macros, this file will not be needed at all. - -'config.in' - This file is created by 'autoheader' based on 'acconfig.h' and - 'configure.in'. At build time, the configure script will define - some of the macros in it to create 'config.h', which may then be - included by your program. This permits your C code to use - preprocessor conditionals to change its behaviour based on the - characteristics of the host system. This file may also be called - 'config.h.in'. - -'stamp.h-in' - This rather uninteresting file, which I omitted from the picture, - is generated by 'automake'. It always contains the string - 'timestamp'. It is used as a timestamp file indicating whether - 'config.in' is up to date. Using a timestamp file means that - 'config.in' can be marked as up to date without actually changing - its modification time. This is useful since 'config.in' depends - upon 'configure.in', but it is easy to change 'configure.in' in a - way which does not affect 'config.in'. - - -File: configure.info, Node: Build Files, Next: Support Files, Prev: Developer Files, Up: Files - -3.2 Build Files -=============== - -This section describes the files which are created at configure and -build time. These are the files which somebody who builds the package -will see. - - Of course, the developer will also build the package. The -distinction between developer files and build files is not that the -developer does not see the build files, but that somebody who only -builds the package does not have to worry about the developer files. - -* Menu: - -* Build Files Picture:: Build Files Picture. -* Build Files Description:: Build Files Description. - - -File: configure.info, Node: Build Files Picture, Next: Build Files Description, Up: Build Files - -3.2.1 Build Files Picture -------------------------- - -Here is a picture of the files which will be created at build time. -'config.status' is both a created file and a shell script which is run -to create other files, and the picture attempts to show that. - - config.in *configure* Makefile.in - | | | - | v | - | config.status | - | | | - *config.status*<======+==========>*config.status* - | | - v v - config.h Makefile - -File: configure.info, Node: Build Files Description, Prev: Build Files Picture, Up: Build Files - -3.2.2 Build Files Description ------------------------------ - -This is a description of the files which are created at build time. - -'config.status' - The first step in building a package is to run the 'configure' - script. The 'configure' script will create the file - 'config.status', which is itself a shell script. When you first - run 'configure', it will automatically run 'config.status'. An - 'Makefile' derived from an automake generated 'Makefile.in' will - contain rules to automatically run 'config.status' again when - necessary to recreate certain files if their inputs change. - -'Makefile' - This is the file which make will read to build the program. The - 'config.status' script will transform 'Makefile.in' into - 'Makefile'. - -'config.h' - This file defines C preprocessor macros which C code can use to - adjust its behaviour on different systems. The 'config.status' - script will transform 'config.in' into 'config.h'. - -'config.cache' - This file did not fit neatly into the picture, and I omitted it. - It is used by the 'configure' script to cache results between runs. - This can be an important speedup. If you modify 'configure.in' in - such a way that the results of old tests should change (perhaps you - have added a new library to 'LDFLAGS'), then you will have to - remove 'config.cache' to force the tests to be rerun. - - The autoconf manual explains how to set up a site specific cache - file. This can speed up running 'configure' scripts on your - system. - -'stamp.h' - This file, which I omitted from the picture, is similar to - 'stamp-h.in'. It is used as a timestamp file indicating whether - 'config.h' is up to date. This is useful since 'config.h' depends - upon 'config.status', but it is easy for 'config.status' to change - in a way which does not affect 'config.h'. - - -File: configure.info, Node: Support Files, Prev: Build Files, Up: Files - -3.3 Support Files -================= - -The GNU configure and build system requires several support files to be -included with your distribution. You do not normally need to concern -yourself with these. If you are using the Cygnus tree, most are already -present. Otherwise, they will be installed with your source by -'automake' (with the '--add-missing' option) and 'libtoolize'. - - You don't have to put the support files in the top level directory. -You can put them in a subdirectory, and use the 'AC_CONFIG_AUX_DIR' -macro in 'configure.in' to tell 'automake' and the 'configure' script -where they are. - - In this section, I describe the support files, so that you can know -what they are and why they are there. - -'ABOUT-NLS' - Added by automake if you are using gettext. This is a - documentation file about the gettext project. -'ansi2knr.c' - Used by an automake generated 'Makefile' if you put 'ansi2knr' in - 'AUTOMAKE_OPTIONS' in 'Makefile.am'. This permits compiling ANSI C - code with a K&R C compiler. -'ansi2knr.1' - The man page which goes with 'ansi2knr.c'. -'config.guess' - A shell script which determines the configuration name for the - system on which it is run. -'config.sub' - A shell script which canonicalizes a configuration name entered by - a user. -'elisp-comp' - Used to compile Emacs LISP files. -'install-sh' - A shell script which installs a program. This is used if the - configure script can not find an install binary. -'ltconfig' - Used by libtool. This is a shell script which configures libtool - for the particular system on which it is used. -'ltmain.sh' - Used by libtool. This is the actual libtool script which is used, - after it is configured by 'ltconfig' to build a library. -'mdate-sh' - A shell script used by an automake generated 'Makefile' to pretty - print the modification time of a file. This is used to maintain - version numbers for texinfo files. -'missing' - A shell script used if some tool is missing entirely. This is used - by an automake generated 'Makefile' to avoid certain sorts of - timestamp problems. -'mkinstalldirs' - A shell script which creates a directory, including all parent - directories. This is used by an automake generated 'Makefile' - during installation. -'texinfo.tex' - Required if you have any texinfo files. This is used when - converting Texinfo files into DVI using 'texi2dvi' and TeX. -'ylwrap' - A shell script used by an automake generated 'Makefile' to run - programs like 'bison', 'yacc', 'flex', and 'lex'. These programs - default to producing output files with a fixed name, and the - 'ylwrap' script runs them in a subdirectory to avoid file name - conflicts when using a parallel make program. - - -File: configure.info, Node: Configuration Names, Next: Cross Compilation Tools, Prev: Files, Up: Top - -4 Configuration Names -********************* - -The GNU configure system names all systems using a "configuration name". -All such names used to be triplets (they may now contain four parts in -certain cases), and the term "configuration triplet" is still seen. - -* Menu: - -* Configuration Name Definition:: Configuration Name Definition. -* Using Configuration Names:: Using Configuration Names. - - -File: configure.info, Node: Configuration Name Definition, Next: Using Configuration Names, Up: Configuration Names - -4.1 Configuration Name Definition -================================= - -This is a string of the form CPU-MANUFACTURER-OPERATING_SYSTEM. In some -cases, this is extended to a four part form: -CPU-MANUFACTURER-KERNEL-OPERATING_SYSTEM. - - When using a configuration name in a configure option, it is normally -not necessary to specify an entire name. In particular, the -MANUFACTURER field is often omitted, leading to strings such as -'i386-linux' or 'sparc-sunos'. The shell script 'config.sub' will -translate these shortened strings into the canonical form. autoconf -will arrange for 'config.sub' to be run automatically when it is needed. - - The fields of a configuration name are as follows: - -CPU - The type of processor. This is typically something like 'i386' or - 'sparc'. More specific variants are used as well, such as 'mipsel' - to indicate a little endian MIPS processor. -MANUFACTURER - A somewhat freeform field which indicates the manufacturer of the - system. This is often simply 'unknown'. Other common strings are - 'pc' for an IBM PC compatible system, or the name of a workstation - vendor, such as 'sun'. -OPERATING_SYSTEM - The name of the operating system which is run on the system. This - will be something like 'solaris2.5' or 'irix6.3'. There is no - particular restriction on the version number, and strings like - 'aix4.1.4.0' are seen. For an embedded system, which has no - operating system, this field normally indicates the type of object - file format, such as 'elf' or 'coff'. -KERNEL - This is used mainly for GNU/Linux. A typical GNU/Linux - configuration name is 'i586-pc-linux-gnulibc1'. In this case the - kernel, 'linux', is separated from the operating system, - 'gnulibc1'. - - The shell script 'config.guess' will normally print the correct -configuration name for the system on which it is run. It does by -running 'uname' and by examining other characteristics of the system. - - Because 'config.guess' can normally determine the configuration name -for a machine, it is normally only necessary to specify a configuration -name when building a cross-compiler or when building using a -cross-compiler. - - -File: configure.info, Node: Using Configuration Names, Prev: Configuration Name Definition, Up: Configuration Names - -4.2 Using Configuration Names -============================= - -A configure script will sometimes have to make a decision based on a -configuration name. You will need to do this if you have to compile -code differently based on something which can not be tested using a -standard autoconf feature test. - - It is normally better to test for particular features, rather than to -test for a particular system. This is because as Unix evolves, -different systems copy features from one another. Even if you need to -determine whether the feature is supported based on a configuration -name, you should define a macro which describes the feature, rather than -defining a macro which describes the particular system you are on. - - Testing for a particular system is normally done using a case -statement in 'configure.in'. The case statement might look something -like the following, assuming that 'host' is a shell variable holding a -canonical configuration name (which will be the case if 'configure.in' -uses the 'AC_CANONICAL_HOST' or 'AC_CANONICAL_SYSTEM' macro). - - case "${host}" in - i[3-7]86-*-linux-gnu*) do something ;; - sparc*-sun-solaris2.[56789]*) do something ;; - sparc*-sun-solaris*) do something ;; - mips*-*-elf*) do something ;; - esac - - It is particularly important to use '*' after the operating system -field, in order to match the version number which will be generated by -'config.guess'. - - In most cases you must be careful to match a range of processor -types. For most processor families, a trailing '*' suffices, as in -'mips*' above. For the i386 family, something along the lines of -'i[3-7]86' suffices at present. For the m68k family, you will need -something like 'm68*'. Of course, if you do not need to match on the -processor, it is simpler to just replace the entire field by a '*', as -in '*-*-irix*'. - - -File: configure.info, Node: Cross Compilation Tools, Next: Canadian Cross, Prev: Configuration Names, Up: Top - -5 Cross Compilation Tools -************************* - -The GNU configure and build system can be used to build "cross -compilation" tools. A cross compilation tool is a tool which runs on -one system and produces code which runs on another system. - -* Menu: - -* Cross Compilation Concepts:: Cross Compilation Concepts. -* Host and Target:: Host and Target. -* Using the Host Type:: Using the Host Type. -* Specifying the Target:: Specifying the Target. -* Using the Target Type:: Using the Target Type. -* Cross Tools in the Cygnus Tree:: Cross Tools in the Cygnus Tree - - -File: configure.info, Node: Cross Compilation Concepts, Next: Host and Target, Up: Cross Compilation Tools - -5.1 Cross Compilation Concepts -============================== - -A compiler which produces programs which run on a different system is a -cross compilation compiler, or simply a "cross compiler". Similarly, we -speak of cross assemblers, cross linkers, etc. - - In the normal case, a compiler produces code which runs on the same -system as the one on which the compiler runs. When it is necessary to -distinguish this case from the cross compilation case, such a compiler -is called a "native compiler". Similarly, we speak of native -assemblers, etc. - - Although the debugger is not strictly speaking a compilation tool, it -is nevertheless meaningful to speak of a cross debugger: a debugger -which is used to debug code which runs on another system. Everything -that is said below about configuring cross compilation tools applies to -the debugger as well. - - -File: configure.info, Node: Host and Target, Next: Using the Host Type, Prev: Cross Compilation Concepts, Up: Cross Compilation Tools - -5.2 Host and Target -=================== - -When building cross compilation tools, there are two different systems -involved: the system on which the tools will run, and the system for -which the tools generate code. - - The system on which the tools will run is called the "host" system. - - The system for which the tools generate code is called the "target" -system. - - For example, suppose you have a compiler which runs on a GNU/Linux -system and generates ELF programs for a MIPS embedded system. In this -case the GNU/Linux system is the host, and the MIPS ELF system is the -target. Such a compiler could be called a GNU/Linux cross MIPS ELF -compiler, or, equivalently, a 'i386-linux-gnu' cross 'mips-elf' -compiler. - - Naturally, most programs are not cross compilation tools. For those -programs, it does not make sense to speak of a target. It only makes -sense to speak of a target for tools like 'gcc' or the 'binutils' which -actually produce running code. For example, it does not make sense to -speak of the target of a tool like 'bison' or 'make'. - - Most cross compilation tools can also serve as native tools. For a -native compilation tool, it is still meaningful to speak of a target. -For a native tool, the target is the same as the host. For example, for -a GNU/Linux native compiler, the host is GNU/Linux, and the target is -also GNU/Linux. - - -File: configure.info, Node: Using the Host Type, Next: Specifying the Target, Prev: Host and Target, Up: Cross Compilation Tools - -5.3 Using the Host Type -======================= - -In almost all cases the host system is the system on which you run the -'configure' script, and on which you build the tools (for the case when -they differ, *note Canadian Cross::). - - If your configure script needs to know the configuration name of the -host system, and the package is not a cross compilation tool and -therefore does not have a target, put 'AC_CANONICAL_HOST' in -'configure.in'. This macro will arrange to define a few shell variables -when the 'configure' script is run. - -'host' - The canonical configuration name of the host. This will normally - be determined by running the 'config.guess' shell script, although - the user is permitted to override this by using an explicit - '--host' option. -'host_alias' - In the unusual case that the user used an explicit '--host' option, - this will be the argument to '--host'. In the normal case, this - will be the same as the 'host' variable. -'host_cpu' -'host_vendor' -'host_os' - The first three parts of the canonical configuration name. - - The shell variables may be used by putting shell code in -'configure.in'. For an example, see *note Using Configuration Names::. - - -File: configure.info, Node: Specifying the Target, Next: Using the Target Type, Prev: Using the Host Type, Up: Cross Compilation Tools - -5.4 Specifying the Target -========================= - -By default, the 'configure' script will assume that the target is the -same as the host. This is the more common case; for example, it leads -to a native compiler rather than a cross compiler. - - If you want to build a cross compilation tool, you must specify the -target explicitly by using the '--target' option when you run -'configure'. The argument to '--target' is the configuration name of -the system for which you wish to generate code. *Note Configuration -Names::. - - For example, to build tools which generate code for a MIPS ELF -embedded system, you would use '--target mips-elf'. - - -File: configure.info, Node: Using the Target Type, Next: Cross Tools in the Cygnus Tree, Prev: Specifying the Target, Up: Cross Compilation Tools - -5.5 Using the Target Type -========================= - -When writing 'configure.in' for a cross compilation tool, you will need -to use information about the target. To do this, put -'AC_CANONICAL_SYSTEM' in 'configure.in'. - - 'AC_CANONICAL_SYSTEM' will look for a '--target' option and -canonicalize it using the 'config.sub' shell script. It will also run -'AC_CANONICAL_HOST' (*note Using the Host Type::). - - The target type will be recorded in the following shell variables. -Note that the host versions of these variables will also be defined by -'AC_CANONICAL_HOST'. - -'target' - The canonical configuration name of the target. -'target_alias' - The argument to the '--target' option. If the user did not specify - a '--target' option, this will be the same as 'host_alias'. -'target_cpu' -'target_vendor' -'target_os' - The first three parts of the canonical target configuration name. - - Note that if 'host' and 'target' are the same string, you can assume -a native configuration. If they are different, you can assume a cross -configuration. - - It is arguably possible for 'host' and 'target' to represent the same -system, but for the strings to not be identical. For example, if -'config.guess' returns 'sparc-sun-sunos4.1.4', and somebody configures -with '--target sparc-sun-sunos4.1', then the slight differences between -the two versions of SunOS may be unimportant for your tool. However, in -the general case it can be quite difficult to determine whether the -differences between two configuration names are significant or not. -Therefore, by convention, if the user specifies a '--target' option -without specifying a '--host' option, it is assumed that the user wants -to configure a cross compilation tool. - - The variables 'target' and 'target_alias' should be handled -differently. - - In general, whenever the user may actually see a string, -'target_alias' should be used. This includes anything which may appear -in the file system, such as a directory name or part of a tool name. It -also includes any tool output, unless it is clearly labelled as the -canonical target configuration name. This permits the user to use the -'--target' option to specify how the tool will appear to the outside -world. - - On the other hand, when checking for characteristics of the target -system, 'target' should be used. This is because a wide variety of -'--target' options may map into the same canonical configuration name. -You should not attempt to duplicate the canonicalization done by -'config.sub' in your own code. - - By convention, cross tools are installed with a prefix of the -argument used with the '--target' option, also known as 'target_alias' -(*note Using the Target Type::). If the user does not use the -'--target' option, and thus is building a native tool, no prefix is -used. - - For example, if gcc is configured with '--target mips-elf', then the -installed binary will be named 'mips-elf-gcc'. If gcc is configured -without a '--target' option, then the installed binary will be named -'gcc'. - - The autoconf macro 'AC_ARG_PROGRAM' will handle this for you. If you -are using automake, no more need be done; the programs will -automatically be installed with the correct prefixes. Otherwise, see -the autoconf documentation for 'AC_ARG_PROGRAM'. - - -File: configure.info, Node: Cross Tools in the Cygnus Tree, Prev: Using the Target Type, Up: Cross Compilation Tools - -5.6 Cross Tools in the Cygnus Tree -================================== - -The Cygnus tree is used for various packages including gdb, the GNU -binutils, and egcs. It is also, of course, used for Cygnus releases. - - In the Cygnus tree, the top level 'configure' script uses the old -Cygnus configure system, not autoconf. The top level 'Makefile.in' is -written to build packages based on what is in the source tree, and -supports building a large number of tools in a single 'configure'/'make' -step. - - The Cygnus tree may be configured with a '--target' option. The -'--target' option applies recursively to every subdirectory, and permits -building an entire set of cross tools at once. - -* Menu: - -* Host and Target Libraries:: Host and Target Libraries. -* Target Library Configure Scripts:: Target Library Configure Scripts. -* Make Targets in Cygnus Tree:: Make Targets in Cygnus Tree. -* Target libiberty:: Target libiberty - - -File: configure.info, Node: Host and Target Libraries, Next: Target Library Configure Scripts, Up: Cross Tools in the Cygnus Tree - -5.6.1 Host and Target Libraries -------------------------------- - -The Cygnus tree distinguishes host libraries from target libraries. - - Host libraries are built with the compiler used to build the programs -which run on the host, which is called the host compiler. This includes -libraries such as 'bfd' and 'tcl'. These libraries are built with the -host compiler, and are linked into programs like the binutils or gcc -which run on the host. - - Target libraries are built with the target compiler. If gcc is -present in the source tree, then the target compiler is the gcc that is -built using the host compiler. Target libraries are libraries such as -'newlib' and 'libstdc++'. These libraries are not linked into the host -programs, but are instead made available for use with programs built -with the target compiler. - - For the rest of this section, assume that gcc is present in the -source tree, so that it will be used to build the target libraries. - - There is a complication here. The configure process needs to know -which compiler you are going to use to build a tool; otherwise, the -feature tests will not work correctly. The Cygnus tree handles this by -not configuring the target libraries until the target compiler is built. -In order to permit everything to build using a single -'configure'/'make', the configuration of the target libraries is -actually triggered during the make step. - - When the target libraries are configured, the '--target' option is -not used. Instead, the '--host' option is used with the argument of the -'--target' option for the overall configuration. If no '--target' -option was used for the overall configuration, the '--host' option will -be passed with the output of the 'config.guess' shell script. Any -'--build' option is passed down unchanged. - - This translation of configuration options is done because since the -target libraries are compiled with the target compiler, they are being -built in order to run on the target of the overall configuration. By -the definition of host, this means that their host system is the same as -the target system of the overall configuration. - - The same process is used for both a native configuration and a cross -configuration. Even when using a native configuration, the target -libraries will be configured and built using the newly built compiler. -This is particularly important for the C++ libraries, since there is no -reason to assume that the C++ compiler used to build the host tools (if -there even is one) uses the same ABI as the g++ compiler which will be -used to build the target libraries. - - There is one difference between a native configuration and a cross -configuration. In a native configuration, the target libraries are -normally configured and built as siblings of the host tools. In a cross -configuration, the target libraries are normally built in a subdirectory -whose name is the argument to '--target'. This is mainly for historical -reasons. - - To summarize, running 'configure' in the Cygnus tree configures all -the host libraries and tools, but does not configure any of the target -libraries. Running 'make' then does the following steps: - - * Build the host libraries. - * Build the host programs, including gcc. Note that we call gcc both - a host program (since it runs on the host) and a target compiler - (since it generates code for the target). - * Using the newly built target compiler, configure the target - libraries. - * Build the target libraries. - - The steps need not be done in precisely this order, since they are -actually controlled by 'Makefile' targets. - - -File: configure.info, Node: Target Library Configure Scripts, Next: Make Targets in Cygnus Tree, Prev: Host and Target Libraries, Up: Cross Tools in the Cygnus Tree - -5.6.2 Target Library Configure Scripts --------------------------------------- - -There are a few things you must know in order to write a configure -script for a target library. This is just a quick sketch, and beginners -shouldn't worry if they don't follow everything here. - - The target libraries are configured and built using a newly built -target compiler. There may not be any startup files or libraries for -this target compiler. In fact, those files will probably be built as -part of some target library, which naturally means that they will not -exist when your target library is configured. - - This means that the configure script for a target library may not use -any test which requires doing a link. This unfortunately includes many -useful autoconf macros, such as 'AC_CHECK_FUNCS'. autoconf macros which -do a compile but not a link, such as 'AC_CHECK_HEADERS', may be used. - - This is a severe restriction, but normally not a fatal one, as target -libraries can often assume the presence of other target libraries, and -thus know which functions will be available. - - As of this writing, the autoconf macro 'AC_PROG_CC' does a link to -make sure that the compiler works. This may fail in a target library, -so target libraries must use a different set of macros to locate the -compiler. See the 'configure.in' file in a directory like 'libiberty' -or 'libgloss' for an example. - - As noted in the previous section, target libraries are sometimes -built in directories which are siblings to the host tools, and are -sometimes built in a subdirectory. The '--with-target-subdir' configure -option will be passed when the library is configured. Its value will be -an empty string if the target library is a sibling. Its value will be -the name of the subdirectory if the target library is in a subdirectory. - - If the overall build is not a native build (i.e., the overall -configure used the '--target' option), then the library will be -configured with the '--with-cross-host' option. The value of this -option will be the host system of the overall build. Recall that the -host system of the library will be the target of the overall build. If -the overall build is a native build, the '--with-cross-host' option will -not be used. - - A library which can be built both standalone and as a target library -may want to install itself into different directories depending upon the -case. When built standalone, or when built native, the library should -be installed in '$(libdir)'. When built as a target library which is -not native, the library should be installed in '$(tooldir)/lib'. The -'--with-cross-host' option may be used to distinguish these cases. - - This same test of '--with-cross-host' may be used to see whether it -is OK to use link tests in the configure script. If the -'--with-cross-host' option is not used, then the library is being built -either standalone or native, and a link should work. - - -File: configure.info, Node: Make Targets in Cygnus Tree, Next: Target libiberty, Prev: Target Library Configure Scripts, Up: Cross Tools in the Cygnus Tree - -5.6.3 Make Targets in Cygnus Tree ---------------------------------- - -The top level 'Makefile' in the Cygnus tree defines targets for every -known subdirectory. - - For every subdirectory DIR which holds a host library or program, the -'Makefile' target 'all-DIR' will build that library or program. - - There are dependencies among host tools. For example, building gcc -requires first building gas, because the gcc build process invokes the -target assembler. These dependencies are reflected in the top level -'Makefile'. - - For every subdirectory DIR which holds a target library, the -'Makefile' target 'configure-target-DIR' will configure that library. -The 'Makefile' target 'all-target-DIR' will build that library. - - Every 'configure-target-DIR' target depends upon 'all-gcc', since -gcc, the target compiler, is required to configure the tool. Every -'all-target-DIR' target depends upon the corresponding -'configure-target-DIR' target. - - There are several other targets which may be of interest for each -directory: 'install-DIR', 'clean-DIR', and 'check-DIR'. There are also -corresponding 'target' versions of these for the target libraries , such -as 'install-target-DIR'. - - -File: configure.info, Node: Target libiberty, Prev: Make Targets in Cygnus Tree, Up: Cross Tools in the Cygnus Tree - -5.6.4 Target libiberty ----------------------- - -The 'libiberty' subdirectory is currently a special case, in that it is -the only directory which is built both using the host compiler and using -the target compiler. - - This is because the files in 'libiberty' are used when building the -host tools, and they are also incorporated into the 'libstdc++' target -library as support code. - - This duality does not pose any particular difficulties. It means -that there are targets for both 'all-libiberty' and -'all-target-libiberty'. - - In a native configuration, when target libraries are not built in a -subdirectory, the same objects are normally used as both the host build -and the target build. This is normally OK, since libiberty contains -only C code, and in a native configuration the results of the host -compiler and the target compiler are normally interoperable. - - Irix 6 is again an exception here, since the SGI native compiler -defaults to using the 'O32' ABI, and gcc defaults to using the 'N32' -ABI. On Irix 6, the target libraries are built in a subdirectory even -for a native configuration, avoiding this problem. - - There are currently no other libraries built for both the host and -the target, but there is no conceptual problem with adding more. - - -File: configure.info, Node: Canadian Cross, Next: Cygnus Configure, Prev: Cross Compilation Tools, Up: Top - -6 Canadian Cross -**************** - -It is possible to use the GNU configure and build system to build a -program which will run on a system which is different from the system on -which the tools are built. In other words, it is possible to build -programs using a cross compiler. - - This is referred to as a "Canadian Cross". - -* Menu: - -* Canadian Cross Example:: Canadian Cross Example. -* Canadian Cross Concepts:: Canadian Cross Concepts. -* Build Cross Host Tools:: Build Cross Host Tools. -* Build and Host Options:: Build and Host Options. -* CCross not in Cygnus Tree:: Canadian Cross not in Cygnus Tree. -* CCross in Cygnus Tree:: Canadian Cross in Cygnus Tree. -* Supporting Canadian Cross:: Supporting Canadian Cross. - - -File: configure.info, Node: Canadian Cross Example, Next: Canadian Cross Concepts, Up: Canadian Cross - -6.1 Canadian Cross Example -========================== - -Here is an example of a Canadian Cross. - - While running on a GNU/Linux, you can build a program which will run -on a Solaris system. You would use a GNU/Linux cross Solaris compiler -to build the program. - - Of course, you could not run the resulting program on your GNU/Linux -system. You would have to copy it over to a Solaris system before you -would run it. - - Of course, you could also simply build the programs on the Solaris -system in the first place. However, perhaps the Solaris system is not -available for some reason; perhaps you actually don't have one, but you -want to build the tools for somebody else to use. Or perhaps your -GNU/Linux system is much faster than your Solaris system. - - A Canadian Cross build is most frequently used when building programs -to run on a non-Unix system, such as DOS or Windows. It may be simpler -to configure and build on a Unix system than to support the -configuration machinery on a non-Unix system. - - -File: configure.info, Node: Canadian Cross Concepts, Next: Build Cross Host Tools, Prev: Canadian Cross Example, Up: Canadian Cross - -6.2 Canadian Cross Concepts -=========================== - -When building a Canadian Cross, there are at least two different systems -involved: the system on which the tools are being built, and the system -on which the tools will run. - - The system on which the tools are being built is called the "build" -system. - - The system on which the tools will run is called the host system. - - For example, if you are building a Solaris program on a GNU/Linux -system, as in the previous section, the build system would be GNU/Linux, -and the host system would be Solaris. - - It is, of course, possible to build a cross compiler using a Canadian -Cross (i.e., build a cross compiler using a cross compiler). In this -case, the system for which the resulting cross compiler generates code -is called the target system. (For a more complete discussion of host -and target systems, *note Host and Target::). - - An example of building a cross compiler using a Canadian Cross would -be building a Windows cross MIPS ELF compiler on a GNU/Linux system. In -this case the build system would be GNU/Linux, the host system would be -Windows, and the target system would be MIPS ELF. - - The name Canadian Cross comes from the case when the build, host, and -target systems are all different. At the time that these issues were -all being hashed out, Canada had three national political parties. - - -File: configure.info, Node: Build Cross Host Tools, Next: Build and Host Options, Prev: Canadian Cross Concepts, Up: Canadian Cross - -6.3 Build Cross Host Tools -========================== - -In order to configure a program for a Canadian Cross build, you must -first build and install the set of cross tools you will use to build the -program. - - These tools will be build cross host tools. That is, they will run -on the build system, and will produce code that runs on the host system. - - It is easy to confuse the meaning of build and host here. Always -remember that the build system is where you are doing the build, and the -host system is where the resulting program will run. Therefore, you -need a build cross host compiler. - - In general, you must have a complete cross environment in order to do -the build. This normally means a cross compiler, cross assembler, and -so forth, as well as libraries and include files for the host system. - - -File: configure.info, Node: Build and Host Options, Next: CCross not in Cygnus Tree, Prev: Build Cross Host Tools, Up: Canadian Cross - -6.4 Build and Host Options -========================== - -When you run 'configure', you must use both the '--build' and '--host' -options. - - The '--build' option is used to specify the configuration name of the -build system. This can normally be the result of running the -'config.guess' shell script, and it is reasonable to use -'--build=`config.guess`'. - - The '--host' option is used to specify the configuration name of the -host system. - - As we explained earlier, 'config.guess' is used to set the default -value for the '--host' option (*note Using the Host Type::). We can now -see that since 'config.guess' returns the type of system on which it is -run, it really identifies the build system. Since the host system is -normally the same as the build system (i.e., people do not normally -build using a cross compiler), it is reasonable to use the result of -'config.guess' as the default for the host system when the '--host' -option is not used. - - It might seem that if the '--host' option were used without the -'--build' option that the configure script could run 'config.guess' to -determine the build system, and presume a Canadian Cross if the result -of 'config.guess' differed from the '--host' option. However, for -historical reasons, some configure scripts are routinely run using an -explicit '--host' option, rather than using the default from -'config.guess'. As noted earlier, it is difficult or impossible to -reliably compare configuration names (*note Using the Target Type::). -Therefore, by convention, if the '--host' option is used, but the -'--build' option is not used, then the build system defaults to the host -system. - - -File: configure.info, Node: CCross not in Cygnus Tree, Next: CCross in Cygnus Tree, Prev: Build and Host Options, Up: Canadian Cross - -6.5 Canadian Cross not in Cygnus Tree. -====================================== - -If you are not using the Cygnus tree, you must explicitly specify the -cross tools which you want to use to build the program. This is done by -setting environment variables before running the 'configure' script. - - You must normally set at least the environment variables 'CC', 'AR', -and 'RANLIB' to the cross tools which you want to use to build. - - For some programs, you must set additional cross tools as well, such -as 'AS', 'LD', or 'NM'. - - You would set these environment variables to the build cross tools -which you are going to use. - - For example, if you are building a Solaris program on a GNU/Linux -system, and your GNU/Linux cross Solaris compiler were named -'solaris-gcc', then you would set the environment variable 'CC' to -'solaris-gcc'. - - -File: configure.info, Node: CCross in Cygnus Tree, Next: Supporting Canadian Cross, Prev: CCross not in Cygnus Tree, Up: Canadian Cross - -6.6 Canadian Cross in Cygnus Tree -================================= - -This section describes configuring and building a Canadian Cross when -using the Cygnus tree. - -* Menu: - -* Standard Cygnus CCross:: Building a Normal Program. -* Cross Cygnus CCross:: Building a Cross Program. - - -File: configure.info, Node: Standard Cygnus CCross, Next: Cross Cygnus CCross, Up: CCross in Cygnus Tree - -6.6.1 Building a Normal Program -------------------------------- - -When configuring a Canadian Cross in the Cygnus tree, all the -appropriate environment variables are automatically set to 'HOST-TOOL', -where HOST is the value used for the '--host' option, and TOOL is the -name of the tool (e.g., 'gcc', 'as', etc.). These tools must be on your -'PATH'. - - Adding a prefix of HOST will give the usual name for the build cross -host tools. To see this, consider that when these cross tools were -built, they were configured to run on the build system and to produce -code for the host system. That is, they were configured with a -'--target' option that is the same as the system which we are now -calling the host. Recall that the default name for installed cross -tools uses the target system as a prefix (*note Using the Target -Type::). Since that is the system which we are now calling the host, -HOST is the right prefix to use. - - For example, if you configure with '--build=i386-linux-gnu' and -'--host=solaris', then the Cygnus tree will automatically default to -using the compiler 'solaris-gcc'. You must have previously built and -installed this compiler, probably by doing a build with no '--host' -option and with a '--target' option of 'solaris'. - - -File: configure.info, Node: Cross Cygnus CCross, Prev: Standard Cygnus CCross, Up: CCross in Cygnus Tree - -6.6.2 Building a Cross Program ------------------------------- - -There are additional considerations if you want to build a cross -compiler, rather than a native compiler, in the Cygnus tree using a -Canadian Cross. - - When you build a cross compiler using the Cygnus tree, then the -target libraries will normally be built with the newly built target -compiler (*note Host and Target Libraries::). However, this will not -work when building with a Canadian Cross. This is because the newly -built target compiler will be a program which runs on the host system, -and therefore will not be able to run on the build system. - - Therefore, when building a cross compiler with the Cygnus tree, you -must first install a set of build cross target tools. These tools will -be used when building the target libraries. - - Note that this is not a requirement of a Canadian Cross in general. -For example, it would be possible to build just the host cross target -tools on the build system, to copy the tools to the host system, and to -build the target libraries on the host system. The requirement for -build cross target tools is imposed by the Cygnus tree, which expects to -be able to build both host programs and target libraries in a single -'configure'/'make' step. Because it builds these in a single step, it -expects to be able to build the target libraries on the build system, -which means that it must use a build cross target toolchain. - - For example, suppose you want to build a Windows cross MIPS ELF -compiler on a GNU/Linux system. You must have previously installed both -a GNU/Linux cross Windows compiler and a GNU/Linux cross MIPS ELF -compiler. - - In order to build the Windows (configuration name 'i386-cygwin32') -cross MIPS ELF (configure name 'mips-elf') compiler, you might execute -the following commands (long command lines are broken across lines with -a trailing backslash as a continuation character). - - mkdir linux-x-cygwin32 - cd linux-x-cygwin32 - SRCDIR/configure --target i386-cygwin32 --prefix=INSTALLDIR \ - --exec-prefix=INSTALLDIR/H-i386-linux - make - make install - cd .. - mkdir linux-x-mips-elf - cd linux-x-mips-elf - SRCDIR/configure --target mips-elf --prefix=INSTALLDIR \ - --exec-prefix=INSTALLDIR/H-i386-linux - make - make install - cd .. - mkdir cygwin32-x-mips-elf - cd cygwin32-x-mips-elf - SRCDIR/configure --build=i386-linux-gnu --host=i386-cygwin32 \ - --target=mips-elf --prefix=WININSTALLDIR \ - --exec-prefix=WININSTALLDIR/H-i386-cygwin32 - make - make install - - You would then copy the contents of WININSTALLDIR over to the Windows -machine, and run the resulting programs. - - -File: configure.info, Node: Supporting Canadian Cross, Prev: CCross in Cygnus Tree, Up: Canadian Cross - -6.7 Supporting Canadian Cross -============================= - -If you want to make it possible to build a program you are developing -using a Canadian Cross, you must take some care when writing your -configure and make rules. Simple cases will normally work correctly. -However, it is not hard to write configure and make tests which will -fail in a Canadian Cross. - -* Menu: - -* CCross in Configure:: Supporting Canadian Cross in Configure Scripts. -* CCross in Make:: Supporting Canadian Cross in Makefiles. - - -File: configure.info, Node: CCross in Configure, Next: CCross in Make, Up: Supporting Canadian Cross - -6.7.1 Supporting Canadian Cross in Configure Scripts ----------------------------------------------------- - -In a 'configure.in' file, after calling 'AC_PROG_CC', you can find out -whether this is a Canadian Cross configure by examining the shell -variable 'cross_compiling'. In a Canadian Cross, which means that the -compiler is a cross compiler, 'cross_compiling' will be 'yes'. In a -normal configuration, 'cross_compiling' will be 'no'. - - You ordinarily do not need to know the type of the build system in a -configure script. However, if you do need that information, you can get -it by using the macro 'AC_CANONICAL_SYSTEM', the same macro that is used -to determine the target system. This macro will set the variables -'build', 'build_alias', 'build_cpu', 'build_vendor', and 'build_os', -which correspond to the similar 'target' and 'host' variables, except -that they describe the build system. - - When writing tests in 'configure.in', you must remember that you want -to test the host environment, not the build environment. - - Macros like 'AC_CHECK_FUNCS' which use the compiler will test the -host environment. That is because the tests will be done by running the -compiler, which is actually a build cross host compiler. If the -compiler can find the function, that means that the function is present -in the host environment. - - Tests like 'test -f /dev/ptyp0', on the other hand, will test the -build environment. Remember that the configure script is running on the -build system, not the host system. If your configure scripts examines -files, those files will be on the build system. Whatever you determine -based on those files may or may not be the case on the host system. - - Most autoconf macros will work correctly for a Canadian Cross. The -main exception is 'AC_TRY_RUN'. This macro tries to compile and run a -test program. This will fail in a Canadian Cross, because the program -will be compiled for the host system, which means that it will not run -on the build system. - - The 'AC_TRY_RUN' macro provides an optional argument to tell the -configure script what to do in a Canadian Cross. If that argument is -not present, you will get a warning when you run 'autoconf': - warning: AC_TRY_RUN called without default to allow cross compiling -This tells you that the resulting 'configure' script will not work with -a Canadian Cross. - - In some cases while it may better to perform a test at configure -time, it is also possible to perform the test at run time. In such a -case you can use the cross compiling argument to 'AC_TRY_RUN' to tell -your program that the test could not be performed at configure time. - - There are a few other autoconf macros which will not work correctly -with a Canadian Cross: a partial list is 'AC_FUNC_GETPGRP', -'AC_FUNC_SETPGRP', 'AC_FUNC_SETVBUF_REVERSED', and -'AC_SYS_RESTARTABLE_SYSCALLS'. The 'AC_CHECK_SIZEOF' macro is generally -not very useful with a Canadian Cross; it permits an optional argument -indicating the default size, but there is no way to know what the -correct default should be. - - -File: configure.info, Node: CCross in Make, Prev: CCross in Configure, Up: Supporting Canadian Cross - -6.7.2 Supporting Canadian Cross in Makefiles. ---------------------------------------------- - -The main Canadian Cross issue in a 'Makefile' arises when you want to -use a subsidiary program to generate code or data which you will then -include in your real program. - - If you compile this subsidiary program using '$(CC)' in the usual -way, you will not be able to run it. This is because '$(CC)' will build -a program for the host system, but the program is being built on the -build system. - - You must instead use a compiler for the build system, rather than the -host system. In the Cygnus tree, this make variable '$(CC_FOR_BUILD)' -will hold a compiler for the build system. - - Note that you should not include 'config.h' in a file you are -compiling with '$(CC_FOR_BUILD)'. The 'configure' script will build -'config.h' with information for the host system. However, you are -compiling the file using a compiler for the build system (a native -compiler). Subsidiary programs are normally simple filters which do no -user interaction, and it is normally possible to write them in a highly -portable fashion so that the absence of 'config.h' is not crucial. - - The gcc 'Makefile.in' shows a complex situation in which certain -files, such as 'rtl.c', must be compiled into both subsidiary programs -run on the build system and into the final program. This approach may -be of interest for advanced build system hackers. Note that the build -system compiler is rather confusingly called 'HOST_CC'. - - -File: configure.info, Node: Cygnus Configure, Next: Multilibs, Prev: Canadian Cross, Up: Top - -7 Cygnus Configure -****************** - -The Cygnus configure script predates autoconf. All of its interesting -features have been incorporated into autoconf. No new programs should -be written to use the Cygnus configure script. - - However, the Cygnus configure script is still used in a few places: -at the top of the Cygnus tree and in a few target libraries in the -Cygnus tree. Until those uses have been replaced with autoconf, some -brief notes are appropriate here. This is not complete documentation, -but it should be possible to use this as a guide while examining the -scripts themselves. - -* Menu: - -* Cygnus Configure Basics:: Cygnus Configure Basics. -* Cygnus Configure in C++ Libraries:: Cygnus Configure in C++ Libraries. - - -File: configure.info, Node: Cygnus Configure Basics, Next: Cygnus Configure in C++ Libraries, Up: Cygnus Configure - -7.1 Cygnus Configure Basics -=========================== - -Cygnus configure does not use any generated files; there is no program -corresponding to 'autoconf'. Instead, there is a single shell script -named 'configure' which may be found at the top of the Cygnus tree. -This shell script was written by hand; it was not generated by autoconf, -and it is incorrect, and indeed harmful, to run 'autoconf' in the top -level of a Cygnus tree. - - Cygnus configure works in a particular directory by examining the -file 'configure.in' in that directory. That file is broken into four -separate shell scripts. - - The first is the contents of 'configure.in' up to a line that starts -with '# per-host:'. This is the common part. - - The second is the rest of 'configure.in' up to a line that starts -with '# per-target:'. This is the per host part. - - The third is the rest of 'configure.in' up to a line that starts with -'# post-target:'. This is the per target part. - - The fourth is the remainder of 'configure.in'. This is the post -target part. - - If any of these comment lines are missing, the corresponding shell -script is empty. - - Cygnus configure will first execute the common part. This must set -the shell variable 'srctrigger' to the name of a source file, to confirm -that Cygnus configure is looking at the right directory. This may set -the shell variables 'package_makefile_frag' and -'package_makefile_rules_frag'. - - Cygnus configure will next set the 'build' and 'host' shell -variables, and execute the per host part. This may set the shell -variable 'host_makefile_frag'. - - Cygnus configure will next set the 'target' variable, and execute the -per target part. This may set the shell variable -'target_makefile_frag'. - - Any of these scripts may set the 'subdirs' shell variable. This -variable is a list of subdirectories where a 'Makefile.in' file may be -found. Cygnus configure will automatically look for a 'Makefile.in' -file in the current directory. The 'subdirs' shell variable is not -normally used, and I believe that the only directory which uses it at -present is 'newlib'. - - For each 'Makefile.in', Cygnus configure will automatically create a -'Makefile' by adding definitions for 'make' variables such as 'host' and -'target', and automatically editing the values of 'make' variables such -as 'prefix' if they are present. - - Also, if any of the 'makefile_frag' shell variables are set, Cygnus -configure will interpret them as file names relative to either the -working directory or the source directory, and will read the contents of -the file into the generated 'Makefile'. The file contents will be read -in after the first line in 'Makefile.in' which starts with '####'. - - These 'Makefile' fragments are used to customize behaviour for a -particular host or target. They serve to select particular files to -compile, and to define particular preprocessor macros by providing -values for 'make' variables which are then used during compilation. -Cygnus configure, unlike autoconf, normally does not do feature tests, -and normally requires support to be added manually for each new host. - - The 'Makefile' fragment support is similar to the autoconf -'AC_SUBST_FILE' macro. - - After creating each 'Makefile', the post target script will be run -(i.e., it may be run several times). This script may further customize -the 'Makefile'. When it is run, the shell variable 'Makefile' will hold -the name of the 'Makefile', including the appropriate directory -component. - - Like an autoconf generated 'configure' script, Cygnus configure will -create a file named 'config.status' which, when run, will automatically -recreate the configuration. The 'config.status' file will simply -execute the Cygnus configure script again with the appropriate -arguments. - - Any of the parts of 'configure.in' may set the shell variables -'files' and 'links'. Cygnus configure will set up symlinks from the -names in 'links' to the files named in 'files'. This is similar to the -autoconf 'AC_LINK_FILES' macro. - - Finally, any of the parts of 'configure.in' may set the shell -variable 'configdirs' to a set of subdirectories. If it is set, Cygnus -configure will recursively run the configure process in each -subdirectory. If the subdirectory uses Cygnus configure, it will -contain a 'configure.in' file but no 'configure' file, in which case -Cygnus configure will invoke itself recursively. If the subdirectory -has a 'configure' file, Cygnus configure assumes that it is an autoconf -generated 'configure' script, and simply invokes it directly. - - -File: configure.info, Node: Cygnus Configure in C++ Libraries, Prev: Cygnus Configure Basics, Up: Cygnus Configure - -7.2 Cygnus Configure in C++ Libraries -===================================== - -The C++ library configure system, written by Per Bothner, deserves -special mention. It uses Cygnus configure, but it does feature testing -like that done by autoconf generated 'configure' scripts. This approach -is used in the libraries 'libio', 'libstdc++', and 'libg++'. - - Most of the 'Makefile' information is written out by the shell script -'libio/config.shared'. Each 'configure.in' file sets certain shell -variables, and then invokes 'config.shared' to create two package -'Makefile' fragments. These fragments are then incorporated into the -resulting 'Makefile' by the Cygnus configure script. - - The file '_G_config.h' is created in the 'libio' object directory by -running the shell script 'libio/gen-params'. This shell script uses -feature tests to define macros and typedefs in '_G_config.h'. - - -File: configure.info, Node: Multilibs, Next: FAQ, Prev: Cygnus Configure, Up: Top - -8 Multilibs -*********** - -For some targets gcc may have different processor requirements depending -upon command line options. An obvious example is the '-msoft-float' -option supported on several processors. This option means that the -floating point registers are not available, which means that floating -point operations must be done by calling an emulation subroutine rather -than by using machine instructions. - - For such options, gcc is often configured to compile target libraries -twice: once with '-msoft-float' and once without. When gcc compiles -target libraries more than once, the resulting libraries are called -"multilibs". - - Multilibs are not really part of the GNU configure and build system, -but we discuss them here since they require support in the 'configure' -scripts and 'Makefile's used for target libraries. - -* Menu: - -* Multilibs in gcc:: Multilibs in gcc. -* Multilibs in Target Libraries:: Multilibs in Target Libraries. - - -File: configure.info, Node: Multilibs in gcc, Next: Multilibs in Target Libraries, Up: Multilibs - -8.1 Multilibs in gcc -==================== - -In gcc, multilibs are defined by setting the variable 'MULTILIB_OPTIONS' -in the target 'Makefile' fragment. Several other 'MULTILIB' variables -may also be defined there. *Note The Target Makefile Fragment: -(gcc)Target Fragment. - - If you have built gcc, you can see what multilibs it uses by running -it with the '-print-multi-lib' option. The output '.;' means that no -multilibs are used. In general, the output is a sequence of lines, one -per multilib. The first part of each line, up to the ';', is the name -of the multilib directory. The second part is a list of compiler -options separated by '@' characters. - - Multilibs are built in a tree of directories. The top of the tree, -represented by '.' in the list of multilib directories, is the default -library to use when no special compiler options are used. The -subdirectories of the tree hold versions of the library to use when -particular compiler options are used. - - -File: configure.info, Node: Multilibs in Target Libraries, Prev: Multilibs in gcc, Up: Multilibs - -8.2 Multilibs in Target Libraries -================================= - -The target libraries in the Cygnus tree are automatically built with -multilibs. That means that each library is built multiple times. - - This default is set in the top level 'configure.in' file, by adding -'--enable-multilib' to the list of arguments passed to configure when it -is run for the target libraries (*note Host and Target Libraries::). - - Each target library uses the shell script 'config-ml.in', written by -Doug Evans, to prepare to build target libraries. This shell script is -invoked after the 'Makefile' has been created by the 'configure' script. -If multilibs are not enabled, it does nothing, otherwise it modifies the -'Makefile' to support multilibs. - - The 'config-ml.in' script makes one copy of the 'Makefile' for each -multilib in the appropriate subdirectory. When configuring in the -source directory (which is not recommended), it will build a symlink -tree of the sources in each subdirectory. - - The 'config-ml.in' script sets several variables in the various -'Makefile's. The 'Makefile.in' must have definitions for these -variables already; 'config-ml.in' simply changes the existing values. -The 'Makefile' should use default values for these variables which will -do the right thing in the subdirectories. - -'MULTISRCTOP' - 'config-ml.in' will set this to a sequence of '../' strings, where - the number of strings is the number of multilib levels in the - source tree. The default value should be the empty string. -'MULTIBUILDTOP' - 'config-ml.in' will set this to a sequence of '../' strings, where - the number of strings is number of multilib levels in the object - directory. The default value should be the empty string. This - will differ from 'MULTISRCTOP' when configuring in the source tree - (which is not recommended). -'MULTIDIRS' - In the top level 'Makefile' only, 'config-ml.in' will set this to - the list of multilib subdirectories. The default value should be - the empty string. -'MULTISUBDIR' - 'config-ml.in' will set this to the installed subdirectory name to - use for this subdirectory, with a leading '/'. The default value - shold be the empty string. -'MULTIDO' -'MULTICLEAN' - In the top level 'Makefile' only, 'config-ml.in' will set these - variables to commands to use when doing a recursive make. These - variables should both default to the string 'true', so that by - default nothing happens. - - All references to the parent of the source directory should use the -variable 'MULTISRCTOP'. Instead of writing '$(srcdir)/..', you must -write '$(srcdir)/$(MULTISRCTOP)..'. - - Similarly, references to the parent of the object directory should -use the variable 'MULTIBUILDTOP'. - - In the installation target, the libraries should be installed in the -subdirectory 'MULTISUBDIR'. Instead of installing '$(libdir)/libfoo.a', -install '$(libdir)$(MULTISUBDIR)/libfoo.a'. - - The 'config-ml.in' script also modifies the top level 'Makefile' to -add 'multi-do' and 'multi-clean' targets which are used when building -multilibs. - - The default target of the 'Makefile' should include the following -command: - @$(MULTIDO) $(FLAGS_TO_PASS) DO=all multi-do -This assumes that '$(FLAGS_TO_PASS)' is defined as a set of variables to -pass to a recursive invocation of 'make'. This will build all the -multilibs. Note that the default value of 'MULTIDO' is 'true', so by -default this command will do nothing. It will only do something in the -top level 'Makefile' if multilibs were enabled. - - The 'install' target of the 'Makefile' should include the following -command: - @$(MULTIDO) $(FLAGS_TO_PASS) DO=install multi-do - - In general, any operation, other than clean, which should be -performed on all the multilibs should use a '$(MULTIDO)' line, setting -the variable 'DO' to the target of each recursive call to 'make'. - - The 'clean' targets ('clean', 'mostlyclean', etc.) should use -'$(MULTICLEAN)'. For example, the 'clean' target should do this: - @$(MULTICLEAN) DO=clean multi-clean - - -File: configure.info, Node: FAQ, Next: Index, Prev: Multilibs, Up: Top - -9 Frequently Asked Questions -**************************** - -Which do I run first, 'autoconf' or 'automake'? - Except when you first add autoconf or automake support to a - package, you shouldn't run either by hand. Instead, configure with - the '--enable-maintainer-mode' option, and let 'make' take care of - it. - -'autoconf' says something about undefined macros. - This means that you have macros in your 'configure.in' which are - not defined by 'autoconf'. You may be using an old version of - 'autoconf'; try building and installing a newer one. Make sure the - newly installled 'autoconf' is first on your 'PATH'. Also, see the - next question. - -My 'configure' script has stuff like 'CY_GNU_GETTEXT' in it. - This means that you have macros in your 'configure.in' which should - be defined in your 'aclocal.m4' file, but aren't. This usually - means that 'aclocal' was not able to appropriate definitions of the - macros. Make sure that you have installed all the packages you - need. In particular, make sure that you have installed libtool - (this is where 'AM_PROG_LIBTOOL' is defined) and gettext (this is - where 'CY_GNU_GETTEXT' is defined, at least in the Cygnus version - of gettext). - -My 'Makefile' has '@' characters in it. - This may mean that you tried to use an autoconf substitution in - your 'Makefile.in' without adding the appropriate 'AC_SUBST' call - to your 'configure' script. Or it may just mean that you need to - rebuild 'Makefile' in your build directory. To rebuild 'Makefile' - from 'Makefile.in', run the shell script 'config.status' with no - arguments. If you need to force 'configure' to run again, first - run 'config.status --recheck'. These runs are normally done - automatically by 'Makefile' targets, but if your 'Makefile' has - gotten messed up you'll need to help them along. - -Why do I have to run both 'config.status --recheck' and 'config.status'? - Normally, you don't; they will be run automatically by 'Makefile' - targets. If you do need to run them, use 'config.status --recheck' - to run the 'configure' script again with the same arguments as the - first time you ran it. Use 'config.status' (with no arguments) to - regenerate all files ('Makefile', 'config.h', etc.) based on the - results of the configure script. The two cases are separate - because it isn't always necessary to regenerate all the files after - running 'config.status --recheck'. The 'Makefile' targets - generated by automake will use the environment variables - 'CONFIG_FILES' and 'CONFIG_HEADERS' to only regenerate files as - they are needed. - -What is the Cygnus tree? - The Cygnus tree is used for various packages including gdb, the GNU - binutils, and egcs. It is also, of course, used for Cygnus - releases. It is the build system which was developed at Cygnus, - using the Cygnus configure script. It permits building many - different packages with a single configure and make. The configure - scripts in the tree are being converted to autoconf, but the - general build structure remains intact. - -Why do I have to keep rebuilding and reinstalling the tools? - I know, it's a pain. Unfortunately, there are bugs in the tools - themselves which need to be fixed, and each time that happens - everybody who uses the tools need to reinstall new versions of - them. I don't know if there is going to be a clever fix until the - tools stabilize. - -Why not just have a Cygnus tree 'make' target to update the tools? - The tools unfortunately need to be installed before they can be - used. That means that they must be built using an appropriate - prefix, and it seems unwise to assume that every configuration uses - an appropriate prefix. It might be possible to make them work in - place, or it might be possible to install them in some - subdirectory; so far these approaches have not been implemented. - - -File: configure.info, Node: Index, Prev: FAQ, Up: Top - -Index -***** - -[index] -* Menu: - -* '--build' option: Build and Host Options. - (line 9) -* '--host' option: Build and Host Options. - (line 14) -* '--target' option: Specifying the Target. - (line 10) -* '_GNU_SOURCE': Write configure.in. (line 132) -* 'acconfig.h': Written Developer Files. - (line 27) -* 'acconfig.h', writing: Write acconfig.h. (line 6) -* 'acinclude.m4': Written Developer Files. - (line 37) -* 'aclocal.m4': Generated Developer Files. - (line 33) -* 'AC_CANONICAL_HOST': Using the Host Type. (line 10) -* 'AC_CANONICAL_SYSTEM': Using the Target Type. - (line 6) -* 'AC_CONFIG_HEADER': Write configure.in. (line 64) -* 'AC_EXEEXT': Write configure.in. (line 84) -* 'AC_INIT': Write configure.in. (line 37) -* 'AC_OUTPUT': Write configure.in. (line 140) -* 'AC_PREREQ': Write configure.in. (line 41) -* 'AC_PROG_CC': Write configure.in. (line 101) -* 'AC_PROG_CXX': Write configure.in. (line 115) -* 'AM_CONFIG_HEADER': Write configure.in. (line 52) -* 'AM_DISABLE_SHARED': Write configure.in. (line 125) -* 'AM_EXEEXT': Write configure.in. (line 84) -* 'AM_INIT_AUTOMAKE': Write configure.in. (line 47) -* 'AM_MAINTAINER_MODE': Write configure.in. (line 68) -* 'AM_PROG_LIBTOOL': Write configure.in. (line 120) -* 'AM_PROG_LIBTOOL' in 'configure': FAQ. (line 19) -* build option: Build and Host Options. - (line 9) -* building with a cross compiler: Canadian Cross. (line 6) -* canadian cross: Canadian Cross. (line 6) -* canadian cross in configure: CCross in Configure. (line 6) -* canadian cross in cygnus tree: CCross in Cygnus Tree. - (line 6) -* canadian cross in makefile: CCross in Make. (line 6) -* canadian cross, configuring: Build and Host Options. - (line 6) -* canonical system names: Configuration Names. (line 6) -* 'config.cache': Build Files Description. - (line 28) -* 'config.h': Build Files Description. - (line 23) -* 'config.h.in': Generated Developer Files. - (line 45) -* 'config.in': Generated Developer Files. - (line 45) -* 'config.status': Build Files Description. - (line 9) -* 'config.status --recheck': FAQ. (line 40) -* configuration names: Configuration Names. (line 6) -* configuration triplets: Configuration Names. (line 6) -* 'configure': Generated Developer Files. - (line 21) -* configure build system: Build and Host Options. - (line 9) -* configure host: Build and Host Options. - (line 14) -* configure target: Specifying the Target. - (line 10) -* 'configure.in': Written Developer Files. - (line 9) -* 'configure.in', writing: Write configure.in. (line 6) -* configuring a canadian cross: Build and Host Options. - (line 6) -* cross compiler: Cross Compilation Concepts. - (line 6) -* cross compiler, building with: Canadian Cross. (line 6) -* cross tools: Cross Compilation Tools. - (line 6) -* cygnus configure: Cygnus Configure. (line 6) -* 'CY_GNU_GETTEXT' in 'configure': FAQ. (line 19) -* goals: Goals. (line 6) -* history: History. (line 6) -* host names: Configuration Names. (line 6) -* host option: Build and Host Options. - (line 14) -* host system: Host and Target. (line 6) -* host triplets: Configuration Names. (line 6) -* 'HOST_CC': CCross in Make. (line 27) -* 'libg++' configure: Cygnus Configure in C++ Libraries. - (line 6) -* 'libio' configure: Cygnus Configure in C++ Libraries. - (line 6) -* 'libstdc++' configure: Cygnus Configure in C++ Libraries. - (line 6) -* 'Makefile': Build Files Description. - (line 18) -* 'Makefile', garbage characters: FAQ. (line 29) -* 'Makefile.am': Written Developer Files. - (line 18) -* 'Makefile.am', writing: Write Makefile.am. (line 6) -* 'Makefile.in': Generated Developer Files. - (line 26) -* multilibs: Multilibs. (line 6) -* 'stamp-h': Build Files Description. - (line 40) -* 'stamp-h.in': Generated Developer Files. - (line 54) -* system names: Configuration Names. (line 6) -* system types: Configuration Names. (line 6) -* target option: Specifying the Target. - (line 10) -* target system: Host and Target. (line 6) -* triplets: Configuration Names. (line 6) -* undefined macros: FAQ. (line 12) - - - -Tag Table: -Node: Top966 -Node: Introduction1494 -Node: Goals2576 -Node: Tools3300 -Node: History4289 -Node: Building7285 -Node: Getting Started10548 -Node: Write configure.in11061 -Node: Write Makefile.am18275 -Node: Write acconfig.h21431 -Node: Generate files22968 -Node: Getting Started Example24934 -Node: Getting Started Example 125689 -Node: Getting Started Example 227610 -Node: Getting Started Example 330605 -Node: Generate Files in Example32966 -Node: Files34052 -Node: Developer Files34663 -Node: Developer Files Picture35043 -Node: Written Developer Files36343 -Node: Generated Developer Files38895 -Node: Build Files42039 -Node: Build Files Picture42700 -Node: Build Files Description43463 -Node: Support Files45463 -Node: Configuration Names48332 -Node: Configuration Name Definition48831 -Node: Using Configuration Names51151 -Node: Cross Compilation Tools53121 -Node: Cross Compilation Concepts53812 -Node: Host and Target54780 -Node: Using the Host Type56281 -Node: Specifying the Target57628 -Node: Using the Target Type58417 -Node: Cross Tools in the Cygnus Tree61847 -Node: Host and Target Libraries62904 -Node: Target Library Configure Scripts66649 -Node: Make Targets in Cygnus Tree69741 -Node: Target libiberty71089 -Node: Canadian Cross72475 -Node: Canadian Cross Example73316 -Node: Canadian Cross Concepts74435 -Node: Build Cross Host Tools75947 -Node: Build and Host Options76899 -Node: CCross not in Cygnus Tree78685 -Node: CCross in Cygnus Tree79663 -Node: Standard Cygnus CCross80084 -Node: Cross Cygnus CCross81448 -Node: Supporting Canadian Cross84248 -Node: CCross in Configure84863 -Node: CCross in Make88028 -Node: Cygnus Configure89631 -Node: Cygnus Configure Basics90466 -Node: Cygnus Configure in C++ Libraries95144 -Node: Multilibs96151 -Node: Multilibs in gcc97196 -Node: Multilibs in Target Libraries98274 -Node: FAQ102458 -Node: Index106559 - -End Tag Table diff --git a/libc/share/info/standards.info b/libc/share/info/standards.info deleted file mode 100644 index ba33f70..0000000 --- a/libc/share/info/standards.info +++ /dev/null @@ -1,5720 +0,0 @@ -This is standards.info, produced by makeinfo version 6.0 from -standards.texi. - -The GNU coding standards, last updated April 12, 2010. - - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -Foundation, Inc. - - Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with no Front-Cover Texts, and with no Back-Cover -Texts. A copy of the license is included in the section entitled "GNU -Free Documentation License". -INFO-DIR-SECTION GNU organization -START-INFO-DIR-ENTRY -* Standards: (standards). GNU coding standards. -END-INFO-DIR-ENTRY - - -File: standards.info, Node: Top, Next: Preface, Prev: (dir), Up: (dir) - -Version -******* - -The GNU coding standards, last updated April 12, 2010. - - Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -Foundation, Inc. - - Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.3 or -any later version published by the Free Software Foundation; with no -Invariant Sections, with no Front-Cover Texts, and with no Back-Cover -Texts. A copy of the license is included in the section entitled "GNU -Free Documentation License". - -* Menu: - -* Preface:: About the GNU Coding Standards. -* Legal Issues:: Keeping free software free. -* Design Advice:: General program design. -* Program Behavior:: Program behavior for all programs -* Writing C:: Making the best use of C. -* Documentation:: Documenting programs. -* Managing Releases:: The release process. -* References:: Mentioning non-free software or documentation. -* GNU Free Documentation License:: Copying and sharing this manual. -* Index:: - - -File: standards.info, Node: Preface, Next: Legal Issues, Up: Top - -1 About the GNU Coding Standards -******************************** - -The GNU Coding Standards were written by Richard Stallman and other GNU -Project volunteers. Their purpose is to make the GNU system clean, -consistent, and easy to install. This document can also be read as a -guide to writing portable, robust and reliable programs. It focuses on -programs written in C, but many of the rules and principles are useful -even if you write in another programming language. The rules often -state reasons for writing in a certain way. - - If you did not obtain this file directly from the GNU project and -recently, please check for a newer version. You can get the GNU Coding -Standards from the GNU web server in many different formats, including -the Texinfo source, PDF, HTML, DVI, plain text, and more, at: -. - - If you are maintaining an official GNU package, in addition to this -document, please read and follow the GNU maintainer information (*note -Contents: (maintain)Top.). - - If you want to receive diffs for every change to these GNU documents, -join the mailing list 'gnustandards-commit@gnu.org', via the web -interface at -. Archives -are also available there. - - Please send corrections or suggestions for this document to -. If you make a suggestion, please include a -suggested new wording for it, to help us consider the suggestion -efficiently. We prefer a context diff to the Texinfo source, but if -that's difficult for you, you can make a context diff for some other -version of this document, or propose it in any way that makes it clear. -The source repository for this document can be found at -. - - These standards cover the minimum of what is important when writing a -GNU package. Likely, the need for additional standards will come up. -Sometimes, you might suggest that such standards be added to this -document. If you think your standards would be generally useful, please -do suggest them. - - You should also set standards for your package on many questions not -addressed or not firmly specified here. The most important point is to -be self-consistent--try to stick to the conventions you pick, and try to -document them as much as possible. That way, your program will be more -maintainable by others. - - The GNU Hello program serves as an example of how to follow the GNU -coding standards for a trivial program. -. - - This release of the GNU Coding Standards was last updated April 12, -2010. - - -File: standards.info, Node: Legal Issues, Next: Design Advice, Prev: Preface, Up: Top - -2 Keeping Free Software Free -**************************** - -This chapter discusses how you can make sure that GNU software avoids -legal difficulties, and other related issues. - -* Menu: - -* Reading Non-Free Code:: Referring to proprietary programs. -* Contributions:: Accepting contributions. -* Trademarks:: How we deal with trademark issues. - - -File: standards.info, Node: Reading Non-Free Code, Next: Contributions, Up: Legal Issues - -2.1 Referring to Proprietary Programs -===================================== - -Don't in any circumstances refer to Unix source code for or during your -work on GNU! (Or to any other proprietary programs.) - - If you have a vague recollection of the internals of a Unix program, -this does not absolutely mean you can't write an imitation of it, but do -try to organize the imitation internally along different lines, because -this is likely to make the details of the Unix version irrelevant and -dissimilar to your results. - - For example, Unix utilities were generally optimized to minimize -memory use; if you go for speed instead, your program will be very -different. You could keep the entire input file in memory and scan it -there instead of using stdio. Use a smarter algorithm discovered more -recently than the Unix program. Eliminate use of temporary files. Do -it in one pass instead of two (we did this in the assembler). - - Or, on the contrary, emphasize simplicity instead of speed. For some -applications, the speed of today's computers makes simpler algorithms -adequate. - - Or go for generality. For example, Unix programs often have static -tables or fixed-size strings, which make for arbitrary limits; use -dynamic allocation instead. Make sure your program handles NULs and -other funny characters in the input files. Add a programming language -for extensibility and write part of the program in that language. - - Or turn some parts of the program into independently usable -libraries. Or use a simple garbage collector instead of tracking -precisely when to free memory, or use a new GNU facility such as -obstacks. - - -File: standards.info, Node: Contributions, Next: Trademarks, Prev: Reading Non-Free Code, Up: Legal Issues - -2.2 Accepting Contributions -=========================== - -If the program you are working on is copyrighted by the Free Software -Foundation, then when someone else sends you a piece of code to add to -the program, we need legal papers to use it--just as we asked you to -sign papers initially. _Each_ person who makes a nontrivial -contribution to a program must sign some sort of legal papers in order -for us to have clear title to the program; the main author alone is not -enough. - - So, before adding in any contributions from other people, please tell -us, so we can arrange to get the papers. Then wait until we tell you -that we have received the signed papers, before you actually use the -contribution. - - This applies both before you release the program and afterward. If -you receive diffs to fix a bug, and they make significant changes, we -need legal papers for that change. - - This also applies to comments and documentation files. For copyright -law, comments and code are just text. Copyright applies to all kinds of -text, so we need legal papers for all kinds. - - We know it is frustrating to ask for legal papers; it's frustrating -for us as well. But if you don't wait, you are going out on a limb--for -example, what if the contributor's employer won't sign a disclaimer? -You might have to take that code out again! - - You don't need papers for changes of a few lines here or there, since -they are not significant for copyright purposes. Also, you don't need -papers if all you get from the suggestion is some ideas, not actual code -which you use. For example, if someone sent you one implementation, but -you write a different implementation of the same idea, you don't need to -get papers. - - The very worst thing is if you forget to tell us about the other -contributor. We could be very embarrassed in court some day as a -result. - - We have more detailed advice for maintainers of programs; if you have -reached the stage of actually maintaining a program for GNU (whether -released or not), please ask us for a copy. It is also available online -for your perusal: . - - -File: standards.info, Node: Trademarks, Prev: Contributions, Up: Legal Issues - -2.3 Trademarks -============== - -Please do not include any trademark acknowledgements in GNU software -packages or documentation. - - Trademark acknowledgements are the statements that such-and-such is a -trademark of so-and-so. The GNU Project has no objection to the basic -idea of trademarks, but these acknowledgements feel like kowtowing, and -there is no legal requirement for them, so we don't use them. - - What is legally required, as regards other people's trademarks, is to -avoid using them in ways which a reader might reasonably understand as -naming or labeling our own programs or activities. For example, since -"Objective C" is (or at least was) a trademark, we made sure to say that -we provide a "compiler for the Objective C language" rather than an -"Objective C compiler". The latter would have been meant as a shorter -way of saying the former, but it does not explicitly state the -relationship, so it could be misinterpreted as using "Objective C" as a -label for the compiler rather than for the language. - - Please don't use "win" as an abbreviation for Microsoft Windows in -GNU software or documentation. In hacker terminology, calling something -a "win" is a form of praise. If you wish to praise Microsoft Windows -when speaking on your own, by all means do so, but not in GNU software. -Usually we write the name "Windows" in full, but when brevity is very -important (as in file names and sometimes symbol names), we abbreviate -it to "w". For instance, the files and functions in Emacs that deal -with Windows start with 'w32'. - - -File: standards.info, Node: Design Advice, Next: Program Behavior, Prev: Legal Issues, Up: Top - -3 General Program Design -************************ - -This chapter discusses some of the issues you should take into account -when designing your program. - -* Menu: - -* Source Language:: Which languages to use. -* Compatibility:: Compatibility with other implementations. -* Using Extensions:: Using non-standard features. -* Standard C:: Using standard C features. -* Conditional Compilation:: Compiling code only if a conditional is true. - - -File: standards.info, Node: Source Language, Next: Compatibility, Up: Design Advice - -3.1 Which Languages to Use -========================== - -When you want to use a language that gets compiled and runs at high -speed, the best language to use is C. Using another language is like -using a non-standard feature: it will cause trouble for users. Even if -GCC supports the other language, users may find it inconvenient to have -to install the compiler for that other language in order to build your -program. For example, if you write your program in C++, people will -have to install the GNU C++ compiler in order to compile your program. - - C has one other advantage over C++ and other compiled languages: more -people know C, so more people will find it easy to read and modify the -program if it is written in C. - - So in general it is much better to use C, rather than the comparable -alternatives. - - But there are two exceptions to that conclusion: - - * It is no problem to use another language to write a tool - specifically intended for use with that language. That is because - the only people who want to build the tool will be those who have - installed the other language anyway. - - * If an application is of interest only to a narrow part of the - community, then the question of which language it is written in has - less effect on other people, so you may as well please yourself. - - Many programs are designed to be extensible: they include an -interpreter for a language that is higher level than C. Often much of -the program is written in that language, too. The Emacs editor -pioneered this technique. - - The standard extensibility interpreter for GNU software is Guile -(), which implements the language -Scheme (an especially clean and simple dialect of Lisp). Guile also -includes bindings for GTK+/GNOME, making it practical to write modern -GUI functionality within Guile. We don't reject programs written in -other "scripting languages" such as Perl and Python, but using Guile is -very important for the overall consistency of the GNU system. - - -File: standards.info, Node: Compatibility, Next: Using Extensions, Prev: Source Language, Up: Design Advice - -3.2 Compatibility with Other Implementations -============================================ - -With occasional exceptions, utility programs and libraries for GNU -should be upward compatible with those in Berkeley Unix, and upward -compatible with Standard C if Standard C specifies their behavior, and -upward compatible with POSIX if POSIX specifies their behavior. - - When these standards conflict, it is useful to offer compatibility -modes for each of them. - - Standard C and POSIX prohibit many kinds of extensions. Feel free to -make the extensions anyway, and include a '--ansi', '--posix', or -'--compatible' option to turn them off. However, if the extension has a -significant chance of breaking any real programs or scripts, then it is -not really upward compatible. So you should try to redesign its -interface to make it upward compatible. - - Many GNU programs suppress extensions that conflict with POSIX if the -environment variable 'POSIXLY_CORRECT' is defined (even if it is defined -with a null value). Please make your program recognize this variable if -appropriate. - - When a feature is used only by users (not by programs or command -files), and it is done poorly in Unix, feel free to replace it -completely with something totally different and better. (For example, -'vi' is replaced with Emacs.) But it is nice to offer a compatible -feature as well. (There is a free 'vi' clone, so we offer it.) - - Additional useful features are welcome regardless of whether there is -any precedent for them. - - -File: standards.info, Node: Using Extensions, Next: Standard C, Prev: Compatibility, Up: Design Advice - -3.3 Using Non-standard Features -=============================== - -Many GNU facilities that already exist support a number of convenient -extensions over the comparable Unix facilities. Whether to use these -extensions in implementing your program is a difficult question. - - On the one hand, using the extensions can make a cleaner program. On -the other hand, people will not be able to build the program unless the -other GNU tools are available. This might cause the program to work on -fewer kinds of machines. - - With some extensions, it might be easy to provide both alternatives. -For example, you can define functions with a "keyword" 'INLINE' and -define that as a macro to expand into either 'inline' or nothing, -depending on the compiler. - - In general, perhaps it is best not to use the extensions if you can -straightforwardly do without them, but to use the extensions if they are -a big improvement. - - An exception to this rule are the large, established programs (such -as Emacs) which run on a great variety of systems. Using GNU extensions -in such programs would make many users unhappy, so we don't do that. - - Another exception is for programs that are used as part of -compilation: anything that must be compiled with other compilers in -order to bootstrap the GNU compilation facilities. If these require the -GNU compiler, then no one can compile them without having them installed -already. That would be extremely troublesome in certain cases. - - -File: standards.info, Node: Standard C, Next: Conditional Compilation, Prev: Using Extensions, Up: Design Advice - -3.4 Standard C and Pre-Standard C -================================= - -1989 Standard C is widespread enough now that it is ok to use its -features in new programs. There is one exception: do not ever use the -"trigraph" feature of Standard C. - - 1999 Standard C is not widespread yet, so please do not require its -features in programs. It is ok to use its features if they are present. - - However, it is easy to support pre-standard compilers in most -programs, so if you know how to do that, feel free. If a program you -are maintaining has such support, you should try to keep it working. - - To support pre-standard C, instead of writing function definitions in -standard prototype form, - - int - foo (int x, int y) - ... - -write the definition in pre-standard style like this, - - int - foo (x, y) - int x, y; - ... - -and use a separate declaration to specify the argument prototype: - - int foo (int, int); - - You need such a declaration anyway, in a header file, to get the -benefit of prototypes in all the files where the function is called. -And once you have the declaration, you normally lose nothing by writing -the function definition in the pre-standard style. - - This technique does not work for integer types narrower than 'int'. -If you think of an argument as being of a type narrower than 'int', -declare it as 'int' instead. - - There are a few special cases where this technique is hard to use. -For example, if a function argument needs to hold the system type -'dev_t', you run into trouble, because 'dev_t' is shorter than 'int' on -some machines; but you cannot use 'int' instead, because 'dev_t' is -wider than 'int' on some machines. There is no type you can safely use -on all machines in a non-standard definition. The only way to support -non-standard C and pass such an argument is to check the width of -'dev_t' using Autoconf and choose the argument type accordingly. This -may not be worth the trouble. - - In order to support pre-standard compilers that do not recognize -prototypes, you may want to use a preprocessor macro like this: - - /* Declare the prototype for a general external function. */ - #if defined (__STDC__) || defined (WINDOWSNT) - #define P_(proto) proto - #else - #define P_(proto) () - #endif - - -File: standards.info, Node: Conditional Compilation, Prev: Standard C, Up: Design Advice - -3.5 Conditional Compilation -=========================== - -When supporting configuration options already known when building your -program we prefer using 'if (... )' over conditional compilation, as in -the former case the compiler is able to perform more extensive checking -of all possible code paths. - - For example, please write - - if (HAS_FOO) - ... - else - ... - -instead of: - - #ifdef HAS_FOO - ... - #else - ... - #endif - - A modern compiler such as GCC will generate exactly the same code in -both cases, and we have been using similar techniques with good success -in several projects. Of course, the former method assumes that -'HAS_FOO' is defined as either 0 or 1. - - While this is not a silver bullet solving all portability problems, -and is not always appropriate, following this policy would have saved -GCC developers many hours, or even days, per year. - - In the case of function-like macros like 'REVERSIBLE_CC_MODE' in GCC -which cannot be simply used in 'if (...)' statements, there is an easy -workaround. Simply introduce another macro 'HAS_REVERSIBLE_CC_MODE' as -in the following example: - - #ifdef REVERSIBLE_CC_MODE - #define HAS_REVERSIBLE_CC_MODE 1 - #else - #define HAS_REVERSIBLE_CC_MODE 0 - #endif - - -File: standards.info, Node: Program Behavior, Next: Writing C, Prev: Design Advice, Up: Top - -4 Program Behavior for All Programs -*********************************** - -This chapter describes conventions for writing robust software. It also -describes general standards for error messages, the command line -interface, and how libraries should behave. - -* Menu: - -* Non-GNU Standards:: We consider standards such as POSIX; - we don't "obey" them. -* Semantics:: Writing robust programs. -* Libraries:: Library behavior. -* Errors:: Formatting error messages. -* User Interfaces:: Standards about interfaces generally. -* Graphical Interfaces:: Standards for graphical interfaces. -* Command-Line Interfaces:: Standards for command line interfaces. -* Option Table:: Table of long options. -* OID Allocations:: Table of OID slots for GNU. -* Memory Usage:: When and how to care about memory needs. -* File Usage:: Which files to use, and where. - - -File: standards.info, Node: Non-GNU Standards, Next: Semantics, Up: Program Behavior - -4.1 Non-GNU Standards -===================== - -The GNU Project regards standards published by other organizations as -suggestions, not orders. We consider those standards, but we do not -"obey" them. In developing a GNU program, you should implement an -outside standard's specifications when that makes the GNU system better -overall in an objective sense. When it doesn't, you shouldn't. - - In most cases, following published standards is convenient for -users--it means that their programs or scripts will work more portably. -For instance, GCC implements nearly all the features of Standard C as -specified by that standard. C program developers would be unhappy if it -did not. And GNU utilities mostly follow specifications of POSIX.2; -shell script writers and users would be unhappy if our programs were -incompatible. - - But we do not follow either of these specifications rigidly, and -there are specific points on which we decided not to follow them, so as -to make the GNU system better for users. - - For instance, Standard C says that nearly all extensions to C are -prohibited. How silly! GCC implements many extensions, some of which -were later adopted as part of the standard. If you want these -constructs to give an error message as "required" by the standard, you -must specify '--pedantic', which was implemented only so that we can say -"GCC is a 100% implementation of the standard," not because there is any -reason to actually use it. - - POSIX.2 specifies that 'df' and 'du' must output sizes by default in -units of 512 bytes. What users want is units of 1k, so that is what we -do by default. If you want the ridiculous behavior "required" by POSIX, -you must set the environment variable 'POSIXLY_CORRECT' (which was -originally going to be named 'POSIX_ME_HARDER'). - - GNU utilities also depart from the letter of the POSIX.2 -specification when they support long-named command-line options, and -intermixing options with ordinary arguments. This minor incompatibility -with POSIX is never a problem in practice, and it is very useful. - - In particular, don't reject a new feature, or remove an old one, -merely because a standard says it is "forbidden" or "deprecated." - - -File: standards.info, Node: Semantics, Next: Libraries, Prev: Non-GNU Standards, Up: Program Behavior - -4.2 Writing Robust Programs -=========================== - -Avoid arbitrary limits on the length or number of _any_ data structure, -including file names, lines, files, and symbols, by allocating all data -structures dynamically. In most Unix utilities, "long lines are -silently truncated". This is not acceptable in a GNU utility. - - Utilities reading files should not drop NUL characters, or any other -nonprinting characters _including those with codes above 0177_. The -only sensible exceptions would be utilities specifically intended for -interface to certain types of terminals or printers that can't handle -those characters. Whenever possible, try to make programs work properly -with sequences of bytes that represent multibyte characters, using -encodings such as UTF-8 and others. - - Check every system call for an error return, unless you know you wish -to ignore errors. Include the system error text (from 'perror' or -equivalent) in _every_ error message resulting from a failing system -call, as well as the name of the file if any and the name of the -utility. Just "cannot open foo.c" or "stat failed" is not sufficient. - - Check every call to 'malloc' or 'realloc' to see if it returned zero. -Check 'realloc' even if you are making the block smaller; in a system -that rounds block sizes to a power of 2, 'realloc' may get a different -block if you ask for less space. - - In Unix, 'realloc' can destroy the storage block if it returns zero. -GNU 'realloc' does not have this bug: if it fails, the original block is -unchanged. Feel free to assume the bug is fixed. If you wish to run -your program on Unix, and wish to avoid lossage in this case, you can -use the GNU 'malloc'. - - You must expect 'free' to alter the contents of the block that was -freed. Anything you want to fetch from the block, you must fetch before -calling 'free'. - - If 'malloc' fails in a noninteractive program, make that a fatal -error. In an interactive program (one that reads commands from the -user), it is better to abort the command and return to the command -reader loop. This allows the user to kill other processes to free up -virtual memory, and then try the command again. - - Use 'getopt_long' to decode arguments, unless the argument syntax -makes this unreasonable. - - When static storage is to be written in during program execution, use -explicit C code to initialize it. Reserve C initialized declarations -for data that will not be changed. - - Try to avoid low-level interfaces to obscure Unix data structures -(such as file directories, utmp, or the layout of kernel memory), since -these are less likely to work compatibly. If you need to find all the -files in a directory, use 'readdir' or some other high-level interface. -These are supported compatibly by GNU. - - The preferred signal handling facilities are the BSD variant of -'signal', and the POSIX 'sigaction' function; the alternative USG -'signal' interface is an inferior design. - - Nowadays, using the POSIX signal functions may be the easiest way to -make a program portable. If you use 'signal', then on GNU/Linux systems -running GNU libc version 1, you should include 'bsd/signal.h' instead of -'signal.h', so as to get BSD behavior. It is up to you whether to -support systems where 'signal' has only the USG behavior, or give up on -them. - - In error checks that detect "impossible" conditions, just abort. -There is usually no point in printing any message. These checks -indicate the existence of bugs. Whoever wants to fix the bugs will have -to read the source code and run a debugger. So explain the problem with -comments in the source. The relevant data will be in variables, which -are easy to examine with the debugger, so there is no point moving them -elsewhere. - - Do not use a count of errors as the exit status for a program. _That -does not work_, because exit status values are limited to 8 bits (0 -through 255). A single run of the program might have 256 errors; if you -try to return 256 as the exit status, the parent process will see 0 as -the status, and it will appear that the program succeeded. - - If you make temporary files, check the 'TMPDIR' environment variable; -if that variable is defined, use the specified directory instead of -'/tmp'. - - In addition, be aware that there is a possible security problem when -creating temporary files in world-writable directories. In C, you can -avoid this problem by creating temporary files in this manner: - - fd = open (filename, O_WRONLY | O_CREAT | O_EXCL, 0600); - -or by using the 'mkstemps' function from libiberty. - - In bash, use 'set -C' to avoid this problem. - - -File: standards.info, Node: Libraries, Next: Errors, Prev: Semantics, Up: Program Behavior - -4.3 Library Behavior -==================== - -Try to make library functions reentrant. If they need to do dynamic -storage allocation, at least try to avoid any nonreentrancy aside from -that of 'malloc' itself. - - Here are certain name conventions for libraries, to avoid name -conflicts. - - Choose a name prefix for the library, more than two characters long. -All external function and variable names should start with this prefix. -In addition, there should only be one of these in any given library -member. This usually means putting each one in a separate source file. - - An exception can be made when two external symbols are always used -together, so that no reasonable program could use one without the other; -then they can both go in the same file. - - External symbols that are not documented entry points for the user -should have names beginning with '_'. The '_' should be followed by the -chosen name prefix for the library, to prevent collisions with other -libraries. These can go in the same files with user entry points if you -like. - - Static functions and variables can be used as you like and need not -fit any naming convention. - - -File: standards.info, Node: Errors, Next: User Interfaces, Prev: Libraries, Up: Program Behavior - -4.4 Formatting Error Messages -============================= - -Error messages from compilers should look like this: - - SOURCE-FILE-NAME:LINENO: MESSAGE - -If you want to mention the column number, use one of these formats: - - SOURCE-FILE-NAME:LINENO:COLUMN: MESSAGE - SOURCE-FILE-NAME:LINENO.COLUMN: MESSAGE - - -Line numbers should start from 1 at the beginning of the file, and -column numbers should start from 1 at the beginning of the line. (Both -of these conventions are chosen for compatibility.) Calculate column -numbers assuming that space and all ASCII printing characters have equal -width, and assuming tab stops every 8 columns. - - The error message can also give both the starting and ending -positions of the erroneous text. There are several formats so that you -can avoid redundant information such as a duplicate line number. Here -are the possible formats: - - SOURCE-FILE-NAME:LINENO-1.COLUMN-1-LINENO-2.COLUMN-2: MESSAGE - SOURCE-FILE-NAME:LINENO-1.COLUMN-1-COLUMN-2: MESSAGE - SOURCE-FILE-NAME:LINENO-1-LINENO-2: MESSAGE - -When an error is spread over several files, you can use this format: - - FILE-1:LINENO-1.COLUMN-1-FILE-2:LINENO-2.COLUMN-2: MESSAGE - - Error messages from other noninteractive programs should look like -this: - - PROGRAM:SOURCE-FILE-NAME:LINENO: MESSAGE - -when there is an appropriate source file, or like this: - - PROGRAM: MESSAGE - -when there is no relevant source file. - - If you want to mention the column number, use this format: - - PROGRAM:SOURCE-FILE-NAME:LINENO:COLUMN: MESSAGE - - In an interactive program (one that is reading commands from a -terminal), it is better not to include the program name in an error -message. The place to indicate which program is running is in the -prompt or with the screen layout. (When the same program runs with -input from a source other than a terminal, it is not interactive and -would do best to print error messages using the noninteractive style.) - - The string MESSAGE should not begin with a capital letter when it -follows a program name and/or file name, because that isn't the -beginning of a sentence. (The sentence conceptually starts at the -beginning of the line.) Also, it should not end with a period. - - Error messages from interactive programs, and other messages such as -usage messages, should start with a capital letter. But they should not -end with a period. - - -File: standards.info, Node: User Interfaces, Next: Graphical Interfaces, Prev: Errors, Up: Program Behavior - -4.5 Standards for Interfaces Generally -====================================== - -Please don't make the behavior of a utility depend on the name used to -invoke it. It is useful sometimes to make a link to a utility with a -different name, and that should not change what it does. - - Instead, use a run time option or a compilation switch or both to -select among the alternate behaviors. - - Likewise, please don't make the behavior of the program depend on the -type of output device it is used with. Device independence is an -important principle of the system's design; do not compromise it merely -to save someone from typing an option now and then. (Variation in error -message syntax when using a terminal is ok, because that is a side issue -that people do not depend on.) - - If you think one behavior is most useful when the output is to a -terminal, and another is most useful when the output is a file or a -pipe, then it is usually best to make the default behavior the one that -is useful with output to a terminal, and have an option for the other -behavior. - - Compatibility requires certain programs to depend on the type of -output device. It would be disastrous if 'ls' or 'sh' did not do so in -the way all users expect. In some of these cases, we supplement the -program with a preferred alternate version that does not depend on the -output device type. For example, we provide a 'dir' program much like -'ls' except that its default output format is always multi-column -format. - - -File: standards.info, Node: Graphical Interfaces, Next: Command-Line Interfaces, Prev: User Interfaces, Up: Program Behavior - -4.6 Standards for Graphical Interfaces -====================================== - -When you write a program that provides a graphical user interface, -please make it work with the X Window System and the GTK+ toolkit unless -the functionality specifically requires some alternative (for example, -"displaying jpeg images while in console mode"). - - In addition, please provide a command-line interface to control the -functionality. (In many cases, the graphical user interface can be a -separate program which invokes the command-line program.) This is so -that the same jobs can be done from scripts. - - Please also consider providing a D-bus interface for use from other -running programs, such as within GNOME. (GNOME used to use CORBA for -this, but that is being phased out.) In addition, consider providing a -library interface (for use from C), and perhaps a keyboard-driven -console interface (for use by users from console mode). Once you are -doing the work to provide the functionality and the graphical interface, -these won't be much extra work. - - -File: standards.info, Node: Command-Line Interfaces, Next: Option Table, Prev: Graphical Interfaces, Up: Program Behavior - -4.7 Standards for Command Line Interfaces -========================================= - -It is a good idea to follow the POSIX guidelines for the command-line -options of a program. The easiest way to do this is to use 'getopt' to -parse them. Note that the GNU version of 'getopt' will normally permit -options anywhere among the arguments unless the special argument '--' is -used. This is not what POSIX specifies; it is a GNU extension. - - Please define long-named options that are equivalent to the -single-letter Unix-style options. We hope to make GNU more user -friendly this way. This is easy to do with the GNU function -'getopt_long'. - - One of the advantages of long-named options is that they can be -consistent from program to program. For example, users should be able -to expect the "verbose" option of any GNU program which has one, to be -spelled precisely '--verbose'. To achieve this uniformity, look at the -table of common long-option names when you choose the option names for -your program (*note Option Table::). - - It is usually a good idea for file names given as ordinary arguments -to be input files only; any output files would be specified using -options (preferably '-o' or '--output'). Even if you allow an output -file name as an ordinary argument for compatibility, try to provide an -option as another way to specify it. This will lead to more consistency -among GNU utilities, and fewer idiosyncrasies for users to remember. - - All programs should support two standard options: '--version' and -'--help'. CGI programs should accept these as command-line options, and -also if given as the 'PATH_INFO'; for instance, visiting - in a browser should output the same -information as invoking 'p.cgi --help' from the command line. - -* Menu: - -* --version:: The standard output for -version. -* --help:: The standard output for -help. - - -File: standards.info, Node: --version, Next: --help, Up: Command-Line Interfaces - -4.7.1 '--version' ------------------ - -The standard '--version' option should direct the program to print -information about its name, version, origin and legal status, all on -standard output, and then exit successfully. Other options and -arguments should be ignored once this is seen, and the program should -not perform its normal function. - - The first line is meant to be easy for a program to parse; the -version number proper starts after the last space. In addition, it -contains the canonical name for this program, in this format: - - GNU Emacs 19.30 - -The program's name should be a constant string; _don't_ compute it from -'argv[0]'. The idea is to state the standard or canonical name for the -program, not its file name. There are other ways to find out the -precise file name where a command is found in 'PATH'. - - If the program is a subsidiary part of a larger package, mention the -package name in parentheses, like this: - - emacsserver (GNU Emacs) 19.30 - -If the package has a version number which is different from this -program's version number, you can mention the package version number -just before the close-parenthesis. - - If you _need_ to mention the version numbers of libraries which are -distributed separately from the package which contains this program, you -can do so by printing an additional line of version info for each -library you want to mention. Use the same format for these lines as for -the first line. - - Please do not mention all of the libraries that the program uses -"just for completeness"--that would produce a lot of unhelpful clutter. -Please mention library version numbers only if you find in practice that -they are very important to you in debugging. - - The following line, after the version number line or lines, should be -a copyright notice. If more than one copyright notice is called for, -put each on a separate line. - - Next should follow a line stating the license, preferably using one -of abbrevations below, and a brief statement that the program is free -software, and that users are free to copy and change it. Also mention -that there is no warranty, to the extent permitted by law. See -recommended wording below. - - It is ok to finish the output with a list of the major authors of the -program, as a way of giving credit. - - Here's an example of output that follows these rules: - - GNU hello 2.3 - Copyright (C) 2007 Free Software Foundation, Inc. - License GPLv3+: GNU GPL version 3 or later - This is free software: you are free to change and redistribute it. - There is NO WARRANTY, to the extent permitted by law. - - You should adapt this to your program, of course, filling in the -proper year, copyright holder, name of program, and the references to -distribution terms, and changing the rest of the wording as necessary. - - This copyright notice only needs to mention the most recent year in -which changes were made--there's no need to list the years for previous -versions' changes. You don't have to mention the name of the program in -these notices, if that is inconvenient, since it appeared in the first -line. (The rules are different for copyright notices in source files; -*note (maintain)Copyright Notices::.) - - Translations of the above lines must preserve the validity of the -copyright notices (*note Internationalization::). If the translation's -character set supports it, the '(C)' should be replaced with the -copyright symbol, as follows: - - (the official copyright symbol, which is the letter C in a circle); - - Write the word "Copyright" exactly like that, in English. Do not -translate it into another language. International treaties recognize -the English word "Copyright"; translations into other languages do not -have legal significance. - - Finally, here is the table of our suggested license abbreviations. -Any abbreviation can be followed by 'vVERSION[+]', meaning that -particular version, or later versions with the '+', as shown above. - - In the case of exceptions for extra permissions with the GPL, we use -'/' for a separator; the version number can follow the license -abbreviation as usual, as in the examples below. - -GPL - GNU General Public License, . - -LGPL - GNU Lesser General Public License, - . - -GPL/Ada - GNU GPL with the exception for Ada. - -Apache - The Apache Software Foundation license, - . - -Artistic - The Artistic license used for Perl, - . - -Expat - The Expat license, . - -MPL - The Mozilla Public License, . - -OBSD - The original (4-clause) BSD license, incompatible with the GNU GPL - . - -PHP - The license used for PHP, . - -public domain - The non-license that is being in the public domain, - . - -Python - The license for Python, . - -RBSD - The revised (3-clause) BSD, compatible with the GNU GPL, - . - -X11 - The simple non-copyleft license used for most versions of the X - Window System, . - -Zlib - The license for Zlib, . - - More information about these licenses and many more are on the GNU -licensing web pages, . - - -File: standards.info, Node: --help, Prev: --version, Up: Command-Line Interfaces - -4.7.2 '--help' --------------- - -The standard '--help' option should output brief documentation for how -to invoke the program, on standard output, then exit successfully. -Other options and arguments should be ignored once this is seen, and the -program should not perform its normal function. - - Near the end of the '--help' option's output, please place lines -giving the email address for bug reports, the package's home page -(normally 'http://www.gnu.org/software/PKG', and the general page for -help using GNU programs. The format should be like this: - - Report bugs to: MAILING-ADDRESS - PKG home page: - General help using GNU software: - - It is ok to mention other appropriate mailing lists and web pages. - - -File: standards.info, Node: Option Table, Next: OID Allocations, Prev: Command-Line Interfaces, Up: Program Behavior - -4.8 Table of Long Options -========================= - -Here is a table of long options used by GNU programs. It is surely -incomplete, but we aim to list all the options that a new program might -want to be compatible with. If you use names not already in the table, -please send a list of them, with their meanings, -so we can update the table. - -'after-date' - '-N' in 'tar'. - -'all' - '-a' in 'du', 'ls', 'nm', 'stty', 'uname', and 'unexpand'. - -'all-text' - '-a' in 'diff'. - -'almost-all' - '-A' in 'ls'. - -'append' - '-a' in 'etags', 'tee', 'time'; '-r' in 'tar'. - -'archive' - '-a' in 'cp'. - -'archive-name' - '-n' in 'shar'. - -'arglength' - '-l' in 'm4'. - -'ascii' - '-a' in 'diff'. - -'assign' - '-v' in 'gawk'. - -'assume-new' - '-W' in 'make'. - -'assume-old' - '-o' in 'make'. - -'auto-check' - '-a' in 'recode'. - -'auto-pager' - '-a' in 'wdiff'. - -'auto-reference' - '-A' in 'ptx'. - -'avoid-wraps' - '-n' in 'wdiff'. - -'background' - For server programs, run in the background. - -'backward-search' - '-B' in 'ctags'. - -'basename' - '-f' in 'shar'. - -'batch' - Used in GDB. - -'baud' - Used in GDB. - -'before' - '-b' in 'tac'. - -'binary' - '-b' in 'cpio' and 'diff'. - -'bits-per-code' - '-b' in 'shar'. - -'block-size' - Used in 'cpio' and 'tar'. - -'blocks' - '-b' in 'head' and 'tail'. - -'break-file' - '-b' in 'ptx'. - -'brief' - Used in various programs to make output shorter. - -'bytes' - '-c' in 'head', 'split', and 'tail'. - -'c++' - '-C' in 'etags'. - -'catenate' - '-A' in 'tar'. - -'cd' - Used in various programs to specify the directory to use. - -'changes' - '-c' in 'chgrp' and 'chown'. - -'classify' - '-F' in 'ls'. - -'colons' - '-c' in 'recode'. - -'command' - '-c' in 'su'; '-x' in GDB. - -'compare' - '-d' in 'tar'. - -'compat' - Used in 'gawk'. - -'compress' - '-Z' in 'tar' and 'shar'. - -'concatenate' - '-A' in 'tar'. - -'confirmation' - '-w' in 'tar'. - -'context' - Used in 'diff'. - -'copyleft' - '-W copyleft' in 'gawk'. - -'copyright' - '-C' in 'ptx', 'recode', and 'wdiff'; '-W copyright' in 'gawk'. - -'core' - Used in GDB. - -'count' - '-q' in 'who'. - -'count-links' - '-l' in 'du'. - -'create' - Used in 'tar' and 'cpio'. - -'cut-mark' - '-c' in 'shar'. - -'cxref' - '-x' in 'ctags'. - -'date' - '-d' in 'touch'. - -'debug' - '-d' in 'make' and 'm4'; '-t' in Bison. - -'define' - '-D' in 'm4'. - -'defines' - '-d' in Bison and 'ctags'. - -'delete' - '-D' in 'tar'. - -'dereference' - '-L' in 'chgrp', 'chown', 'cpio', 'du', 'ls', and 'tar'. - -'dereference-args' - '-D' in 'du'. - -'device' - Specify an I/O device (special file name). - -'diacritics' - '-d' in 'recode'. - -'dictionary-order' - '-d' in 'look'. - -'diff' - '-d' in 'tar'. - -'digits' - '-n' in 'csplit'. - -'directory' - Specify the directory to use, in various programs. In 'ls', it - means to show directories themselves rather than their contents. - In 'rm' and 'ln', it means to not treat links to directories - specially. - -'discard-all' - '-x' in 'strip'. - -'discard-locals' - '-X' in 'strip'. - -'dry-run' - '-n' in 'make'. - -'ed' - '-e' in 'diff'. - -'elide-empty-files' - '-z' in 'csplit'. - -'end-delete' - '-x' in 'wdiff'. - -'end-insert' - '-z' in 'wdiff'. - -'entire-new-file' - '-N' in 'diff'. - -'environment-overrides' - '-e' in 'make'. - -'eof' - '-e' in 'xargs'. - -'epoch' - Used in GDB. - -'error-limit' - Used in 'makeinfo'. - -'error-output' - '-o' in 'm4'. - -'escape' - '-b' in 'ls'. - -'exclude-from' - '-X' in 'tar'. - -'exec' - Used in GDB. - -'exit' - '-x' in 'xargs'. - -'exit-0' - '-e' in 'unshar'. - -'expand-tabs' - '-t' in 'diff'. - -'expression' - '-e' in 'sed'. - -'extern-only' - '-g' in 'nm'. - -'extract' - '-i' in 'cpio'; '-x' in 'tar'. - -'faces' - '-f' in 'finger'. - -'fast' - '-f' in 'su'. - -'fatal-warnings' - '-E' in 'm4'. - -'file' - '-f' in 'gawk', 'info', 'make', 'mt', 'sed', and 'tar'. - -'field-separator' - '-F' in 'gawk'. - -'file-prefix' - '-b' in Bison. - -'file-type' - '-F' in 'ls'. - -'files-from' - '-T' in 'tar'. - -'fill-column' - Used in 'makeinfo'. - -'flag-truncation' - '-F' in 'ptx'. - -'fixed-output-files' - '-y' in Bison. - -'follow' - '-f' in 'tail'. - -'footnote-style' - Used in 'makeinfo'. - -'force' - '-f' in 'cp', 'ln', 'mv', and 'rm'. - -'force-prefix' - '-F' in 'shar'. - -'foreground' - For server programs, run in the foreground; in other words, don't - do anything special to run the server in the background. - -'format' - Used in 'ls', 'time', and 'ptx'. - -'freeze-state' - '-F' in 'm4'. - -'fullname' - Used in GDB. - -'gap-size' - '-g' in 'ptx'. - -'get' - '-x' in 'tar'. - -'graphic' - '-i' in 'ul'. - -'graphics' - '-g' in 'recode'. - -'group' - '-g' in 'install'. - -'gzip' - '-z' in 'tar' and 'shar'. - -'hashsize' - '-H' in 'm4'. - -'header' - '-h' in 'objdump' and 'recode' - -'heading' - '-H' in 'who'. - -'help' - Used to ask for brief usage information. - -'here-delimiter' - '-d' in 'shar'. - -'hide-control-chars' - '-q' in 'ls'. - -'html' - In 'makeinfo', output HTML. - -'idle' - '-u' in 'who'. - -'ifdef' - '-D' in 'diff'. - -'ignore' - '-I' in 'ls'; '-x' in 'recode'. - -'ignore-all-space' - '-w' in 'diff'. - -'ignore-backups' - '-B' in 'ls'. - -'ignore-blank-lines' - '-B' in 'diff'. - -'ignore-case' - '-f' in 'look' and 'ptx'; '-i' in 'diff' and 'wdiff'. - -'ignore-errors' - '-i' in 'make'. - -'ignore-file' - '-i' in 'ptx'. - -'ignore-indentation' - '-I' in 'etags'. - -'ignore-init-file' - '-f' in Oleo. - -'ignore-interrupts' - '-i' in 'tee'. - -'ignore-matching-lines' - '-I' in 'diff'. - -'ignore-space-change' - '-b' in 'diff'. - -'ignore-zeros' - '-i' in 'tar'. - -'include' - '-i' in 'etags'; '-I' in 'm4'. - -'include-dir' - '-I' in 'make'. - -'incremental' - '-G' in 'tar'. - -'info' - '-i', '-l', and '-m' in Finger. - -'init-file' - In some programs, specify the name of the file to read as the - user's init file. - -'initial' - '-i' in 'expand'. - -'initial-tab' - '-T' in 'diff'. - -'inode' - '-i' in 'ls'. - -'interactive' - '-i' in 'cp', 'ln', 'mv', 'rm'; '-e' in 'm4'; '-p' in 'xargs'; '-w' - in 'tar'. - -'intermix-type' - '-p' in 'shar'. - -'iso-8601' - Used in 'date' - -'jobs' - '-j' in 'make'. - -'just-print' - '-n' in 'make'. - -'keep-going' - '-k' in 'make'. - -'keep-files' - '-k' in 'csplit'. - -'kilobytes' - '-k' in 'du' and 'ls'. - -'language' - '-l' in 'etags'. - -'less-mode' - '-l' in 'wdiff'. - -'level-for-gzip' - '-g' in 'shar'. - -'line-bytes' - '-C' in 'split'. - -'lines' - Used in 'split', 'head', and 'tail'. - -'link' - '-l' in 'cpio'. - -'lint' -'lint-old' - Used in 'gawk'. - -'list' - '-t' in 'cpio'; '-l' in 'recode'. - -'list' - '-t' in 'tar'. - -'literal' - '-N' in 'ls'. - -'load-average' - '-l' in 'make'. - -'login' - Used in 'su'. - -'machine' - Used in 'uname'. - -'macro-name' - '-M' in 'ptx'. - -'mail' - '-m' in 'hello' and 'uname'. - -'make-directories' - '-d' in 'cpio'. - -'makefile' - '-f' in 'make'. - -'mapped' - Used in GDB. - -'max-args' - '-n' in 'xargs'. - -'max-chars' - '-n' in 'xargs'. - -'max-lines' - '-l' in 'xargs'. - -'max-load' - '-l' in 'make'. - -'max-procs' - '-P' in 'xargs'. - -'mesg' - '-T' in 'who'. - -'message' - '-T' in 'who'. - -'minimal' - '-d' in 'diff'. - -'mixed-uuencode' - '-M' in 'shar'. - -'mode' - '-m' in 'install', 'mkdir', and 'mkfifo'. - -'modification-time' - '-m' in 'tar'. - -'multi-volume' - '-M' in 'tar'. - -'name-prefix' - '-a' in Bison. - -'nesting-limit' - '-L' in 'm4'. - -'net-headers' - '-a' in 'shar'. - -'new-file' - '-W' in 'make'. - -'no-builtin-rules' - '-r' in 'make'. - -'no-character-count' - '-w' in 'shar'. - -'no-check-existing' - '-x' in 'shar'. - -'no-common' - '-3' in 'wdiff'. - -'no-create' - '-c' in 'touch'. - -'no-defines' - '-D' in 'etags'. - -'no-deleted' - '-1' in 'wdiff'. - -'no-dereference' - '-d' in 'cp'. - -'no-inserted' - '-2' in 'wdiff'. - -'no-keep-going' - '-S' in 'make'. - -'no-lines' - '-l' in Bison. - -'no-piping' - '-P' in 'shar'. - -'no-prof' - '-e' in 'gprof'. - -'no-regex' - '-R' in 'etags'. - -'no-sort' - '-p' in 'nm'. - -'no-splash' - Don't print a startup splash screen. - -'no-split' - Used in 'makeinfo'. - -'no-static' - '-a' in 'gprof'. - -'no-time' - '-E' in 'gprof'. - -'no-timestamp' - '-m' in 'shar'. - -'no-validate' - Used in 'makeinfo'. - -'no-wait' - Used in 'emacsclient'. - -'no-warn' - Used in various programs to inhibit warnings. - -'node' - '-n' in 'info'. - -'nodename' - '-n' in 'uname'. - -'nonmatching' - '-f' in 'cpio'. - -'nstuff' - '-n' in 'objdump'. - -'null' - '-0' in 'xargs'. - -'number' - '-n' in 'cat'. - -'number-nonblank' - '-b' in 'cat'. - -'numeric-sort' - '-n' in 'nm'. - -'numeric-uid-gid' - '-n' in 'cpio' and 'ls'. - -'nx' - Used in GDB. - -'old-archive' - '-o' in 'tar'. - -'old-file' - '-o' in 'make'. - -'one-file-system' - '-l' in 'tar', 'cp', and 'du'. - -'only-file' - '-o' in 'ptx'. - -'only-prof' - '-f' in 'gprof'. - -'only-time' - '-F' in 'gprof'. - -'options' - '-o' in 'getopt', 'fdlist', 'fdmount', 'fdmountd', and 'fdumount'. - -'output' - In various programs, specify the output file name. - -'output-prefix' - '-o' in 'shar'. - -'override' - '-o' in 'rm'. - -'overwrite' - '-c' in 'unshar'. - -'owner' - '-o' in 'install'. - -'paginate' - '-l' in 'diff'. - -'paragraph-indent' - Used in 'makeinfo'. - -'parents' - '-p' in 'mkdir' and 'rmdir'. - -'pass-all' - '-p' in 'ul'. - -'pass-through' - '-p' in 'cpio'. - -'port' - '-P' in 'finger'. - -'portability' - '-c' in 'cpio' and 'tar'. - -'posix' - Used in 'gawk'. - -'prefix-builtins' - '-P' in 'm4'. - -'prefix' - '-f' in 'csplit'. - -'preserve' - Used in 'tar' and 'cp'. - -'preserve-environment' - '-p' in 'su'. - -'preserve-modification-time' - '-m' in 'cpio'. - -'preserve-order' - '-s' in 'tar'. - -'preserve-permissions' - '-p' in 'tar'. - -'print' - '-l' in 'diff'. - -'print-chars' - '-L' in 'cmp'. - -'print-data-base' - '-p' in 'make'. - -'print-directory' - '-w' in 'make'. - -'print-file-name' - '-o' in 'nm'. - -'print-symdefs' - '-s' in 'nm'. - -'printer' - '-p' in 'wdiff'. - -'prompt' - '-p' in 'ed'. - -'proxy' - Specify an HTTP proxy. - -'query-user' - '-X' in 'shar'. - -'question' - '-q' in 'make'. - -'quiet' - Used in many programs to inhibit the usual output. Every program - accepting '--quiet' should accept '--silent' as a synonym. - -'quiet-unshar' - '-Q' in 'shar' - -'quote-name' - '-Q' in 'ls'. - -'rcs' - '-n' in 'diff'. - -'re-interval' - Used in 'gawk'. - -'read-full-blocks' - '-B' in 'tar'. - -'readnow' - Used in GDB. - -'recon' - '-n' in 'make'. - -'record-number' - '-R' in 'tar'. - -'recursive' - Used in 'chgrp', 'chown', 'cp', 'ls', 'diff', and 'rm'. - -'reference' - '-r' in 'touch'. - -'references' - '-r' in 'ptx'. - -'regex' - '-r' in 'tac' and 'etags'. - -'release' - '-r' in 'uname'. - -'reload-state' - '-R' in 'm4'. - -'relocation' - '-r' in 'objdump'. - -'rename' - '-r' in 'cpio'. - -'replace' - '-i' in 'xargs'. - -'report-identical-files' - '-s' in 'diff'. - -'reset-access-time' - '-a' in 'cpio'. - -'reverse' - '-r' in 'ls' and 'nm'. - -'reversed-ed' - '-f' in 'diff'. - -'right-side-defs' - '-R' in 'ptx'. - -'same-order' - '-s' in 'tar'. - -'same-permissions' - '-p' in 'tar'. - -'save' - '-g' in 'stty'. - -'se' - Used in GDB. - -'sentence-regexp' - '-S' in 'ptx'. - -'separate-dirs' - '-S' in 'du'. - -'separator' - '-s' in 'tac'. - -'sequence' - Used by 'recode' to chose files or pipes for sequencing passes. - -'shell' - '-s' in 'su'. - -'show-all' - '-A' in 'cat'. - -'show-c-function' - '-p' in 'diff'. - -'show-ends' - '-E' in 'cat'. - -'show-function-line' - '-F' in 'diff'. - -'show-tabs' - '-T' in 'cat'. - -'silent' - Used in many programs to inhibit the usual output. Every program - accepting '--silent' should accept '--quiet' as a synonym. - -'size' - '-s' in 'ls'. - -'socket' - Specify a file descriptor for a network server to use for its - socket, instead of opening and binding a new socket. This provides - a way to run, in a non-privileged process, a server that normally - needs a reserved port number. - -'sort' - Used in 'ls'. - -'source' - '-W source' in 'gawk'. - -'sparse' - '-S' in 'tar'. - -'speed-large-files' - '-H' in 'diff'. - -'split-at' - '-E' in 'unshar'. - -'split-size-limit' - '-L' in 'shar'. - -'squeeze-blank' - '-s' in 'cat'. - -'start-delete' - '-w' in 'wdiff'. - -'start-insert' - '-y' in 'wdiff'. - -'starting-file' - Used in 'tar' and 'diff' to specify which file within a directory - to start processing with. - -'statistics' - '-s' in 'wdiff'. - -'stdin-file-list' - '-S' in 'shar'. - -'stop' - '-S' in 'make'. - -'strict' - '-s' in 'recode'. - -'strip' - '-s' in 'install'. - -'strip-all' - '-s' in 'strip'. - -'strip-debug' - '-S' in 'strip'. - -'submitter' - '-s' in 'shar'. - -'suffix' - '-S' in 'cp', 'ln', 'mv'. - -'suffix-format' - '-b' in 'csplit'. - -'sum' - '-s' in 'gprof'. - -'summarize' - '-s' in 'du'. - -'symbolic' - '-s' in 'ln'. - -'symbols' - Used in GDB and 'objdump'. - -'synclines' - '-s' in 'm4'. - -'sysname' - '-s' in 'uname'. - -'tabs' - '-t' in 'expand' and 'unexpand'. - -'tabsize' - '-T' in 'ls'. - -'terminal' - '-T' in 'tput' and 'ul'. '-t' in 'wdiff'. - -'text' - '-a' in 'diff'. - -'text-files' - '-T' in 'shar'. - -'time' - Used in 'ls' and 'touch'. - -'timeout' - Specify how long to wait before giving up on some operation. - -'to-stdout' - '-O' in 'tar'. - -'total' - '-c' in 'du'. - -'touch' - '-t' in 'make', 'ranlib', and 'recode'. - -'trace' - '-t' in 'm4'. - -'traditional' - '-t' in 'hello'; '-W traditional' in 'gawk'; '-G' in 'ed', 'm4', - and 'ptx'. - -'tty' - Used in GDB. - -'typedefs' - '-t' in 'ctags'. - -'typedefs-and-c++' - '-T' in 'ctags'. - -'typeset-mode' - '-t' in 'ptx'. - -'uncompress' - '-z' in 'tar'. - -'unconditional' - '-u' in 'cpio'. - -'undefine' - '-U' in 'm4'. - -'undefined-only' - '-u' in 'nm'. - -'update' - '-u' in 'cp', 'ctags', 'mv', 'tar'. - -'usage' - Used in 'gawk'; same as '--help'. - -'uuencode' - '-B' in 'shar'. - -'vanilla-operation' - '-V' in 'shar'. - -'verbose' - Print more information about progress. Many programs support this. - -'verify' - '-W' in 'tar'. - -'version' - Print the version number. - -'version-control' - '-V' in 'cp', 'ln', 'mv'. - -'vgrind' - '-v' in 'ctags'. - -'volume' - '-V' in 'tar'. - -'what-if' - '-W' in 'make'. - -'whole-size-limit' - '-l' in 'shar'. - -'width' - '-w' in 'ls' and 'ptx'. - -'word-regexp' - '-W' in 'ptx'. - -'writable' - '-T' in 'who'. - -'zeros' - '-z' in 'gprof'. - - -File: standards.info, Node: OID Allocations, Next: Memory Usage, Prev: Option Table, Up: Program Behavior - -4.9 OID Allocations -=================== - -The OID (object identifier) 1.3.6.1.4.1.11591 has been assigned to the -GNU Project (thanks to Werner Koch). These are used for SNMP, LDAP, -X.509 certificates, and so on. The web site - has a (voluntary) listing of many -OID assignments. - - If you need a new slot for your GNU package, write -. Here is a list of arcs currently assigned: - - - 1.3.6.1.4.1.11591 GNU - - 1.3.6.1.4.1.11591.1 GNU Radius - - 1.3.6.1.4.1.11591.2 GnuPG - 1.3.6.1.4.1.11591.2.1 notation - 1.3.6.1.4.1.11591.2.1.1 pkaAddress - - 1.3.6.1.4.1.11591.3 GNU Radar - - 1.3.6.1.4.1.11591.4 GNU GSS - - 1.3.6.1.4.1.11591.5 GNU Mailutils - - 1.3.6.1.4.1.11591.6 GNU Shishi - - 1.3.6.1.4.1.11591.7 GNU Radio - - 1.3.6.1.4.1.11591.12 digestAlgorithm - 1.3.6.1.4.1.11591.12.2 TIGER/192 - 1.3.6.1.4.1.11591.13 encryptionAlgorithm - 1.3.6.1.4.1.11591.13.2 Serpent - 1.3.6.1.4.1.11591.13.2.1 Serpent-128-ECB - 1.3.6.1.4.1.11591.13.2.2 Serpent-128-CBC - 1.3.6.1.4.1.11591.13.2.3 Serpent-128-OFB - 1.3.6.1.4.1.11591.13.2.4 Serpent-128-CFB - 1.3.6.1.4.1.11591.13.2.21 Serpent-192-ECB - 1.3.6.1.4.1.11591.13.2.22 Serpent-192-CBC - 1.3.6.1.4.1.11591.13.2.23 Serpent-192-OFB - 1.3.6.1.4.1.11591.13.2.24 Serpent-192-CFB - 1.3.6.1.4.1.11591.13.2.41 Serpent-256-ECB - 1.3.6.1.4.1.11591.13.2.42 Serpent-256-CBC - 1.3.6.1.4.1.11591.13.2.43 Serpent-256-OFB - 1.3.6.1.4.1.11591.13.2.44 Serpent-256-CFB - 1.3.6.1.4.1.11591.14 CRC algorithms - 1.3.6.1.4.1.11591.14.1 CRC 32 - - -File: standards.info, Node: Memory Usage, Next: File Usage, Prev: OID Allocations, Up: Program Behavior - -4.10 Memory Usage -================= - -If a program typically uses just a few meg of memory, don't bother -making any effort to reduce memory usage. For example, if it is -impractical for other reasons to operate on files more than a few meg -long, it is reasonable to read entire input files into memory to operate -on them. - - However, for programs such as 'cat' or 'tail', that can usefully -operate on very large files, it is important to avoid using a technique -that would artificially limit the size of files it can handle. If a -program works by lines and could be applied to arbitrary user-supplied -input files, it should keep only a line in memory, because this is not -very hard and users will want to be able to operate on input files that -are bigger than will fit in memory all at once. - - If your program creates complicated data structures, just make them -in memory and give a fatal error if 'malloc' returns zero. - - -File: standards.info, Node: File Usage, Prev: Memory Usage, Up: Program Behavior - -4.11 File Usage -=============== - -Programs should be prepared to operate when '/usr' and '/etc' are -read-only file systems. Thus, if the program manages log files, lock -files, backup files, score files, or any other files which are modified -for internal purposes, these files should not be stored in '/usr' or -'/etc'. - - There are two exceptions. '/etc' is used to store system -configuration information; it is reasonable for a program to modify -files in '/etc' when its job is to update the system configuration. -Also, if the user explicitly asks to modify one file in a directory, it -is reasonable for the program to store other files in the same -directory. - - -File: standards.info, Node: Writing C, Next: Documentation, Prev: Program Behavior, Up: Top - -5 Making The Best Use of C -************************** - -This chapter provides advice on how best to use the C language when -writing GNU software. - -* Menu: - -* Formatting:: Formatting your source code. -* Comments:: Commenting your work. -* Syntactic Conventions:: Clean use of C constructs. -* Names:: Naming variables, functions, and files. -* System Portability:: Portability among different operating systems. -* CPU Portability:: Supporting the range of CPU types. -* System Functions:: Portability and "standard" library functions. -* Internationalization:: Techniques for internationalization. -* Character Set:: Use ASCII by default. -* Quote Characters:: Use '...' in the C locale. -* Mmap:: How you can safely use 'mmap'. - - -File: standards.info, Node: Formatting, Next: Comments, Up: Writing C - -5.1 Formatting Your Source Code -=============================== - -It is important to put the open-brace that starts the body of a C -function in column one, so that they will start a defun. Several tools -look for open-braces in column one to find the beginnings of C -functions. These tools will not work on code not formatted that way. - - Avoid putting open-brace, open-parenthesis or open-bracket in column -one when they are inside a function, so that they won't start a defun. -The open-brace that starts a 'struct' body can go in column one if you -find it useful to treat that definition as a defun. - - It is also important for function definitions to start the name of -the function in column one. This helps people to search for function -definitions, and may also help certain tools recognize them. Thus, -using Standard C syntax, the format is this: - - static char * - concat (char *s1, char *s2) - { - ... - } - -or, if you want to use traditional C syntax, format the definition like -this: - - static char * - concat (s1, s2) /* Name starts in column one here */ - char *s1, *s2; - { /* Open brace in column one here */ - ... - } - - In Standard C, if the arguments don't fit nicely on one line, split -it like this: - - int - lots_of_args (int an_integer, long a_long, short a_short, - double a_double, float a_float) - ... - - The rest of this section gives our recommendations for other aspects -of C formatting style, which is also the default style of the 'indent' -program in version 1.2 and newer. It corresponds to the options - - -nbad -bap -nbc -bbo -bl -bli2 -bls -ncdb -nce -cp1 -cs -di2 - -ndj -nfc1 -nfca -hnl -i2 -ip5 -lp -pcs -psl -nsc -nsob - - We don't think of these recommendations as requirements, because it -causes no problems for users if two different programs have different -formatting styles. - - But whatever style you use, please use it consistently, since a -mixture of styles within one program tends to look ugly. If you are -contributing changes to an existing program, please follow the style of -that program. - - For the body of the function, our recommended style looks like this: - - if (x < foo (y, z)) - haha = bar[4] + 5; - else - { - while (z) - { - haha += foo (z, z); - z--; - } - return ++x + bar (); - } - - We find it easier to read a program when it has spaces before the -open-parentheses and after the commas. Especially after the commas. - - When you split an expression into multiple lines, split it before an -operator, not after one. Here is the right way: - - if (foo_this_is_long && bar > win (x, y, z) - && remaining_condition) - - Try to avoid having two operators of different precedence at the same -level of indentation. For example, don't write this: - - mode = (inmode[j] == VOIDmode - || GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j]) - ? outmode[j] : inmode[j]); - - Instead, use extra parentheses so that the indentation shows the -nesting: - - mode = ((inmode[j] == VOIDmode - || (GET_MODE_SIZE (outmode[j]) > GET_MODE_SIZE (inmode[j]))) - ? outmode[j] : inmode[j]); - - Insert extra parentheses so that Emacs will indent the code properly. -For example, the following indentation looks nice if you do it by hand, - - v = rup->ru_utime.tv_sec*1000 + rup->ru_utime.tv_usec/1000 - + rup->ru_stime.tv_sec*1000 + rup->ru_stime.tv_usec/1000; - -but Emacs would alter it. Adding a set of parentheses produces -something that looks equally nice, and which Emacs will preserve: - - v = (rup->ru_utime.tv_sec*1000 + rup->ru_utime.tv_usec/1000 - + rup->ru_stime.tv_sec*1000 + rup->ru_stime.tv_usec/1000); - - Format do-while statements like this: - - do - { - a = foo (a); - } - while (a > 0); - - Please use formfeed characters (control-L) to divide the program into -pages at logical places (but not within a function). It does not matter -just how long the pages are, since they do not have to fit on a printed -page. The formfeeds should appear alone on lines by themselves. - - -File: standards.info, Node: Comments, Next: Syntactic Conventions, Prev: Formatting, Up: Writing C - -5.2 Commenting Your Work -======================== - -Every program should start with a comment saying briefly what it is for. -Example: 'fmt - filter for simple filling of text'. This comment should -be at the top of the source file containing the 'main' function of the -program. - - Also, please write a brief comment at the start of each source file, -with the file name and a line or two about the overall purpose of the -file. - - Please write the comments in a GNU program in English, because -English is the one language that nearly all programmers in all countries -can read. If you do not write English well, please write comments in -English as well as you can, then ask other people to help rewrite them. -If you can't write comments in English, please find someone to work with -you and translate your comments into English. - - Please put a comment on each function saying what the function does, -what sorts of arguments it gets, and what the possible values of -arguments mean and are used for. It is not necessary to duplicate in -words the meaning of the C argument declarations, if a C type is being -used in its customary fashion. If there is anything nonstandard about -its use (such as an argument of type 'char *' which is really the -address of the second character of a string, not the first), or any -possible values that would not work the way one would expect (such as, -that strings containing newlines are not guaranteed to work), be sure to -say so. - - Also explain the significance of the return value, if there is one. - - Please put two spaces after the end of a sentence in your comments, -so that the Emacs sentence commands will work. Also, please write -complete sentences and capitalize the first word. If a lower-case -identifier comes at the beginning of a sentence, don't capitalize it! -Changing the spelling makes it a different identifier. If you don't -like starting a sentence with a lower case letter, write the sentence -differently (e.g., "The identifier lower-case is ..."). - - The comment on a function is much clearer if you use the argument -names to speak about the argument values. The variable name itself -should be lower case, but write it in upper case when you are speaking -about the value rather than the variable itself. Thus, "the inode -number NODE_NUM" rather than "an inode". - - There is usually no purpose in restating the name of the function in -the comment before it, because the reader can see that for himself. -There might be an exception when the comment is so long that the -function itself would be off the bottom of the screen. - - There should be a comment on each static variable as well, like this: - - /* Nonzero means truncate lines in the display; - zero means continue them. */ - int truncate_lines; - - Every '#endif' should have a comment, except in the case of short -conditionals (just a few lines) that are not nested. The comment should -state the condition of the conditional that is ending, _including its -sense_. '#else' should have a comment describing the condition _and -sense_ of the code that follows. For example: - - #ifdef foo - ... - #else /* not foo */ - ... - #endif /* not foo */ - #ifdef foo - ... - #endif /* foo */ - -but, by contrast, write the comments this way for a '#ifndef': - - #ifndef foo - ... - #else /* foo */ - ... - #endif /* foo */ - #ifndef foo - ... - #endif /* not foo */ - - -File: standards.info, Node: Syntactic Conventions, Next: Names, Prev: Comments, Up: Writing C - -5.3 Clean Use of C Constructs -============================= - -Please explicitly declare the types of all objects. For example, you -should explicitly declare all arguments to functions, and you should -declare functions to return 'int' rather than omitting the 'int'. - - Some programmers like to use the GCC '-Wall' option, and change the -code whenever it issues a warning. If you want to do this, then do. -Other programmers prefer not to use '-Wall', because it gives warnings -for valid and legitimate code which they do not want to change. If you -want to do this, then do. The compiler should be your servant, not your -master. - - Declarations of external functions and functions to appear later in -the source file should all go in one place near the beginning of the -file (somewhere before the first function definition in the file), or -else should go in a header file. Don't put 'extern' declarations inside -functions. - - It used to be common practice to use the same local variables (with -names like 'tem') over and over for different values within one -function. Instead of doing this, it is better to declare a separate -local variable for each distinct purpose, and give it a name which is -meaningful. This not only makes programs easier to understand, it also -facilitates optimization by good compilers. You can also move the -declaration of each local variable into the smallest scope that includes -all its uses. This makes the program even cleaner. - - Don't use local variables or parameters that shadow global -identifiers. - - Don't declare multiple variables in one declaration that spans lines. -Start a new declaration on each line, instead. For example, instead of -this: - - int foo, - bar; - -write either this: - - int foo, bar; - -or this: - - int foo; - int bar; - -(If they are global variables, each should have a comment preceding it -anyway.) - - When you have an 'if'-'else' statement nested in another 'if' -statement, always put braces around the 'if'-'else'. Thus, never write -like this: - - if (foo) - if (bar) - win (); - else - lose (); - -always like this: - - if (foo) - { - if (bar) - win (); - else - lose (); - } - - If you have an 'if' statement nested inside of an 'else' statement, -either write 'else if' on one line, like this, - - if (foo) - ... - else if (bar) - ... - -with its 'then'-part indented like the preceding 'then'-part, or write -the nested 'if' within braces like this: - - if (foo) - ... - else - { - if (bar) - ... - } - - Don't declare both a structure tag and variables or typedefs in the -same declaration. Instead, declare the structure tag separately and -then use it to declare the variables or typedefs. - - Try to avoid assignments inside 'if'-conditions (assignments inside -'while'-conditions are ok). For example, don't write this: - - if ((foo = (char *) malloc (sizeof *foo)) == 0) - fatal ("virtual memory exhausted"); - -instead, write this: - - foo = (char *) malloc (sizeof *foo); - if (foo == 0) - fatal ("virtual memory exhausted"); - - Don't make the program ugly to placate 'lint'. Please don't insert -any casts to 'void'. Zero without a cast is perfectly fine as a null -pointer constant, except when calling a varargs function. - - -File: standards.info, Node: Names, Next: System Portability, Prev: Syntactic Conventions, Up: Writing C - -5.4 Naming Variables, Functions, and Files -========================================== - -The names of global variables and functions in a program serve as -comments of a sort. So don't choose terse names--instead, look for -names that give useful information about the meaning of the variable or -function. In a GNU program, names should be English, like other -comments. - - Local variable names can be shorter, because they are used only -within one context, where (presumably) comments explain their purpose. - - Try to limit your use of abbreviations in symbol names. It is ok to -make a few abbreviations, explain what they mean, and then use them -frequently, but don't use lots of obscure abbreviations. - - Please use underscores to separate words in a name, so that the Emacs -word commands can be useful within them. Stick to lower case; reserve -upper case for macros and 'enum' constants, and for name-prefixes that -follow a uniform convention. - - For example, you should use names like 'ignore_space_change_flag'; -don't use names like 'iCantReadThis'. - - Variables that indicate whether command-line options have been -specified should be named after the meaning of the option, not after the -option-letter. A comment should state both the exact meaning of the -option and its letter. For example, - - /* Ignore changes in horizontal whitespace (-b). */ - int ignore_space_change_flag; - - When you want to define names with constant integer values, use -'enum' rather than '#define'. GDB knows about enumeration constants. - - You might want to make sure that none of the file names would -conflict if the files were loaded onto an MS-DOS file system which -shortens the names. You can use the program 'doschk' to test for this. - - Some GNU programs were designed to limit themselves to file names of -14 characters or less, to avoid file name conflicts if they are read -into older System V systems. Please preserve this feature in the -existing GNU programs that have it, but there is no need to do this in -new GNU programs. 'doschk' also reports file names longer than 14 -characters. - - -File: standards.info, Node: System Portability, Next: CPU Portability, Prev: Names, Up: Writing C - -5.5 Portability between System Types -==================================== - -In the Unix world, "portability" refers to porting to different Unix -versions. For a GNU program, this kind of portability is desirable, but -not paramount. - - The primary purpose of GNU software is to run on top of the GNU -kernel, compiled with the GNU C compiler, on various types of CPU. So -the kinds of portability that are absolutely necessary are quite -limited. But it is important to support Linux-based GNU systems, since -they are the form of GNU that is popular. - - Beyond that, it is good to support the other free operating systems -(*BSD), and it is nice to support other Unix-like systems if you want -to. Supporting a variety of Unix-like systems is desirable, although -not paramount. It is usually not too hard, so you may as well do it. -But you don't have to consider it an obligation, if it does turn out to -be hard. - - The easiest way to achieve portability to most Unix-like systems is -to use Autoconf. It's unlikely that your program needs to know more -information about the host platform than Autoconf can provide, simply -because most of the programs that need such knowledge have already been -written. - - Avoid using the format of semi-internal data bases (e.g., -directories) when there is a higher-level alternative ('readdir'). - - As for systems that are not like Unix, such as MSDOS, Windows, VMS, -MVS, and older Macintosh systems, supporting them is often a lot of -work. When that is the case, it is better to spend your time adding -features that will be useful on GNU and GNU/Linux, rather than on -supporting other incompatible systems. - - If you do support Windows, please do not abbreviate it as "win". In -hacker terminology, calling something a "win" is a form of praise. -You're free to praise Microsoft Windows on your own if you want, but -please don't do this in GNU packages. Instead of abbreviating "Windows" -to "win", you can write it in full or abbreviate it to "woe" or "w". In -GNU Emacs, for instance, we use 'w32' in file names of Windows-specific -files, but the macro for Windows conditionals is called 'WINDOWSNT'. - - It is a good idea to define the "feature test macro" '_GNU_SOURCE' -when compiling your C files. When you compile on GNU or GNU/Linux, this -will enable the declarations of GNU library extension functions, and -that will usually give you a compiler error message if you define the -same function names in some other way in your program. (You don't have -to actually _use_ these functions, if you prefer to make the program -more portable to other systems.) - - But whether or not you use these GNU extensions, you should avoid -using their names for any other meanings. Doing so would make it hard -to move your code into other GNU programs. - - -File: standards.info, Node: CPU Portability, Next: System Functions, Prev: System Portability, Up: Writing C - -5.6 Portability between CPUs -============================ - -Even GNU systems will differ because of differences among CPU types--for -example, difference in byte ordering and alignment requirements. It is -absolutely essential to handle these differences. However, don't make -any effort to cater to the possibility that an 'int' will be less than -32 bits. We don't support 16-bit machines in GNU. - - Similarly, don't make any effort to cater to the possibility that -'long' will be smaller than predefined types like 'size_t'. For -example, the following code is ok: - - printf ("size = %lu\n", (unsigned long) sizeof array); - printf ("diff = %ld\n", (long) (pointer2 - pointer1)); - - 1989 Standard C requires this to work, and we know of only one -counterexample: 64-bit programs on Microsoft Windows. We will leave it -to those who want to port GNU programs to that environment to figure out -how to do it. - - Predefined file-size types like 'off_t' are an exception: they are -longer than 'long' on many platforms, so code like the above won't work -with them. One way to print an 'off_t' value portably is to print its -digits yourself, one by one. - - Don't assume that the address of an 'int' object is also the address -of its least-significant byte. This is false on big-endian machines. -Thus, don't make the following mistake: - - int c; - ... - while ((c = getchar ()) != EOF) - write (file_descriptor, &c, 1); - -Instead, use 'unsigned char' as follows. (The 'unsigned' is for -portability to unusual systems where 'char' is signed and where there is -integer overflow checking.) - - int c; - while ((c = getchar ()) != EOF) - { - unsigned char u = c; - write (file_descriptor, &u, 1); - } - - It used to be ok to not worry about the difference between pointers -and integers when passing arguments to functions. However, on most -modern 64-bit machines pointers are wider than 'int'. Conversely, -integer types like 'long long int' and 'off_t' are wider than pointers -on most modern 32-bit machines. Hence it's often better nowadays to use -prototypes to define functions whose argument types are not trivial. - - In particular, if functions accept varying argument counts or types -they should be declared using prototypes containing '...' and defined -using 'stdarg.h'. For an example of this, please see the Gnulib -(http://www.gnu.org/software/gnulib/) error module, which declares and -defines the following function: - - /* Print a message with `fprintf (stderr, FORMAT, ...)'; - if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). - If STATUS is nonzero, terminate the program with `exit (STATUS)'. */ - - void error (int status, int errnum, const char *format, ...); - - A simple way to use the Gnulib error module is to obtain the two -source files 'error.c' and 'error.h' from the Gnulib library source code -repository at . -Here's a sample use: - - #include "error.h" - #include - #include - - char *program_name = "myprogram"; - - FILE * - xfopen (char const *name) - { - FILE *fp = fopen (name, "r"); - if (! fp) - error (1, errno, "cannot read %s", name); - return fp; - } - - Avoid casting pointers to integers if you can. Such casts greatly -reduce portability, and in most programs they are easy to avoid. In the -cases where casting pointers to integers is essential--such as, a Lisp -interpreter which stores type information as well as an address in one -word--you'll have to make explicit provisions to handle different word -sizes. You will also need to make provision for systems in which the -normal range of addresses you can get from 'malloc' starts far away from -zero. - - -File: standards.info, Node: System Functions, Next: Internationalization, Prev: CPU Portability, Up: Writing C - -5.7 Calling System Functions -============================ - -C implementations differ substantially. Standard C reduces but does not -eliminate the incompatibilities; meanwhile, many GNU packages still -support pre-standard compilers because this is not hard to do. This -chapter gives recommendations for how to use the more-or-less standard C -library functions to avoid unnecessary loss of portability. - - * Don't use the return value of 'sprintf'. It returns the number of - characters written on some systems, but not on all systems. - - * Be aware that 'vfprintf' is not always available. - - * 'main' should be declared to return type 'int'. It should - terminate either by calling 'exit' or by returning the integer - status code; make sure it cannot ever return an undefined value. - - * Don't declare system functions explicitly. - - Almost any declaration for a system function is wrong on some - system. To minimize conflicts, leave it to the system header files - to declare system functions. If the headers don't declare a - function, let it remain undeclared. - - While it may seem unclean to use a function without declaring it, - in practice this works fine for most system library functions on - the systems where this really happens; thus, the disadvantage is - only theoretical. By contrast, actual declarations have frequently - caused actual conflicts. - - * If you must declare a system function, don't specify the argument - types. Use an old-style declaration, not a Standard C prototype. - The more you specify about the function, the more likely a - conflict. - - * In particular, don't unconditionally declare 'malloc' or 'realloc'. - - Most GNU programs use those functions just once, in functions - conventionally named 'xmalloc' and 'xrealloc'. These functions - call 'malloc' and 'realloc', respectively, and check the results. - - Because 'xmalloc' and 'xrealloc' are defined in your program, you - can declare them in other files without any risk of type conflict. - - On most systems, 'int' is the same length as a pointer; thus, the - calls to 'malloc' and 'realloc' work fine. For the few exceptional - systems (mostly 64-bit machines), you can use *conditionalized* - declarations of 'malloc' and 'realloc'--or put these declarations - in configuration files specific to those systems. - - * The string functions require special treatment. Some Unix systems - have a header file 'string.h'; others have 'strings.h'. Neither - file name is portable. There are two things you can do: use - Autoconf to figure out which file to include, or don't include - either file. - - * If you don't include either strings file, you can't get - declarations for the string functions from the header file in the - usual way. - - That causes less of a problem than you might think. The newer - standard string functions should be avoided anyway because many - systems still don't support them. The string functions you can use - are these: - - strcpy strncpy strcat strncat - strlen strcmp strncmp - strchr strrchr - - The copy and concatenate functions work fine without a declaration - as long as you don't use their values. Using their values without - a declaration fails on systems where the width of a pointer differs - from the width of 'int', and perhaps in other cases. It is trivial - to avoid using their values, so do that. - - The compare functions and 'strlen' work fine without a declaration - on most systems, possibly all the ones that GNU software runs on. - You may find it necessary to declare them *conditionally* on a few - systems. - - The search functions must be declared to return 'char *'. Luckily, - there is no variation in the data type they return. But there is - variation in their names. Some systems give these functions the - names 'index' and 'rindex'; other systems use the names 'strchr' - and 'strrchr'. Some systems support both pairs of names, but - neither pair works on all systems. - - You should pick a single pair of names and use it throughout your - program. (Nowadays, it is better to choose 'strchr' and 'strrchr' - for new programs, since those are the standard names.) Declare - both of those names as functions returning 'char *'. On systems - which don't support those names, define them as macros in terms of - the other pair. For example, here is what to put at the beginning - of your file (or in a header) if you want to use the names 'strchr' - and 'strrchr' throughout: - - #ifndef HAVE_STRCHR - #define strchr index - #endif - #ifndef HAVE_STRRCHR - #define strrchr rindex - #endif - - char *strchr (); - char *strrchr (); - - Here we assume that 'HAVE_STRCHR' and 'HAVE_STRRCHR' are macros -defined in systems where the corresponding functions exist. One way to -get them properly defined is to use Autoconf. - - -File: standards.info, Node: Internationalization, Next: Character Set, Prev: System Functions, Up: Writing C - -5.8 Internationalization -======================== - -GNU has a library called GNU gettext that makes it easy to translate the -messages in a program into various languages. You should use this -library in every program. Use English for the messages as they appear -in the program, and let gettext provide the way to translate them into -other languages. - - Using GNU gettext involves putting a call to the 'gettext' macro -around each string that might need translation--like this: - - printf (gettext ("Processing file `%s'...")); - -This permits GNU gettext to replace the string '"Processing file -`%s'..."' with a translated version. - - Once a program uses gettext, please make a point of writing calls to -'gettext' when you add new strings that call for translation. - - Using GNU gettext in a package involves specifying a "text domain -name" for the package. The text domain name is used to separate the -translations for this package from the translations for other packages. -Normally, the text domain name should be the same as the name of the -package--for example, 'coreutils' for the GNU core utilities. - - To enable gettext to work well, avoid writing code that makes -assumptions about the structure of words or sentences. When you want -the precise text of a sentence to vary depending on the data, use two or -more alternative string constants each containing a complete sentences, -rather than inserting conditionalized words or phrases into a single -sentence framework. - - Here is an example of what not to do: - - printf ("%s is full", capacity > 5000000 ? "disk" : "floppy disk"); - - If you apply gettext to all strings, like this, - - printf (gettext ("%s is full"), - capacity > 5000000 ? gettext ("disk") : gettext ("floppy disk")); - -the translator will hardly know that "disk" and "floppy disk" are meant -to be substituted in the other string. Worse, in some languages (like -French) the construction will not work: the translation of the word -"full" depends on the gender of the first part of the sentence; it -happens to be not the same for "disk" as for "floppy disk". - - Complete sentences can be translated without problems: - - printf (capacity > 5000000 ? gettext ("disk is full") - : gettext ("floppy disk is full")); - - A similar problem appears at the level of sentence structure with -this code: - - printf ("# Implicit rule search has%s been done.\n", - f->tried_implicit ? "" : " not"); - -Adding 'gettext' calls to this code cannot give correct results for all -languages, because negation in some languages requires adding words at -more than one place in the sentence. By contrast, adding 'gettext' -calls does the job straightforwardly if the code starts out like this: - - printf (f->tried_implicit - ? "# Implicit rule search has been done.\n", - : "# Implicit rule search has not been done.\n"); - - Another example is this one: - - printf ("%d file%s processed", nfiles, - nfiles != 1 ? "s" : ""); - -The problem with this example is that it assumes that plurals are made -by adding 's'. If you apply gettext to the format string, like this, - - printf (gettext ("%d file%s processed"), nfiles, - nfiles != 1 ? "s" : ""); - -the message can use different words, but it will still be forced to use -'s' for the plural. Here is a better way, with gettext being applied to -the two strings independently: - - printf ((nfiles != 1 ? gettext ("%d files processed") - : gettext ("%d file processed")), - nfiles); - -But this still doesn't work for languages like Polish, which has three -plural forms: one for nfiles == 1, one for nfiles == 2, 3, 4, 22, 23, -24, ... and one for the rest. The GNU 'ngettext' function solves this -problem: - - printf (ngettext ("%d files processed", "%d file processed", nfiles), - nfiles); - - -File: standards.info, Node: Character Set, Next: Quote Characters, Prev: Internationalization, Up: Writing C - -5.9 Character Set -================= - -Sticking to the ASCII character set (plain text, 7-bit characters) is -preferred in GNU source code comments, text documents, and other -contexts, unless there is good reason to do something else because of -the application domain. For example, if source code deals with the -French Revolutionary calendar, it is OK if its literal strings contain -accented characters in month names like "Flore'al". Also, it is OK to -use non-ASCII characters to represent proper names of contributors in -change logs (*note Change Logs::). - - If you need to use non-ASCII characters, you should normally stick -with one encoding, as one cannot in general mix encodings reliably. - - -File: standards.info, Node: Quote Characters, Next: Mmap, Prev: Character Set, Up: Writing C - -5.10 Quote Characters -===================== - -In the C locale, GNU programs should stick to plain ASCII for quotation -characters in messages to users: preferably 0x60 ('`') for left quotes -and 0x27 (''') for right quotes. It is ok, but not required, to use -locale-specific quotes in other locales. - - The Gnulib (http://www.gnu.org/software/gnulib/) 'quote' and -'quotearg' modules provide a reasonably straightforward way to support -locale-specific quote characters, as well as taking care of other -issues, such as quoting a filename that itself contains a quote -character. See the Gnulib documentation for usage details. - - In any case, the documentation for your program should clearly -specify how it does quoting, if different than the preferred method of -'`' and '''. This is especially important if the output of your program -is ever likely to be parsed by another program. - - Quotation characters are a difficult area in the computing world at -this time: there are no true left or right quote characters in Latin1; -the '`' character we use was standardized there as a grave accent. -Moreover, Latin1 is still not universally usable. - - Unicode contains the unambiguous quote characters required, and its -common encoding UTF-8 is upward compatible with Latin1. However, -Unicode and UTF-8 are not universally well-supported, either. - - This may change over the next few years, and then we will revisit -this. - - -File: standards.info, Node: Mmap, Prev: Quote Characters, Up: Writing C - -5.11 Mmap -========= - -Don't assume that 'mmap' either works on all files or fails for all -files. It may work on some files and fail on others. - - The proper way to use 'mmap' is to try it on the specific file for -which you want to use it--and if 'mmap' doesn't work, fall back on doing -the job in another way using 'read' and 'write'. - - The reason this precaution is needed is that the GNU kernel (the -HURD) provides a user-extensible file system, in which there can be many -different kinds of "ordinary files." Many of them support 'mmap', but -some do not. It is important to make programs handle all these kinds of -files. - - -File: standards.info, Node: Documentation, Next: Managing Releases, Prev: Writing C, Up: Top - -6 Documenting Programs -********************** - -A GNU program should ideally come with full free documentation, adequate -for both reference and tutorial purposes. If the package can be -programmed or extended, the documentation should cover programming or -extending it, as well as just using it. - -* Menu: - -* GNU Manuals:: Writing proper manuals. -* Doc Strings and Manuals:: Compiling doc strings doesn't make a manual. -* Manual Structure Details:: Specific structure conventions. -* License for Manuals:: Writing the distribution terms for a manual. -* Manual Credits:: Giving credit to documentation contributors. -* Printed Manuals:: Mentioning the printed manual. -* NEWS File:: NEWS files supplement manuals. -* Change Logs:: Recording changes. -* Man Pages:: Man pages are secondary. -* Reading other Manuals:: How far you can go in learning - from other manuals. - - -File: standards.info, Node: GNU Manuals, Next: Doc Strings and Manuals, Up: Documentation - -6.1 GNU Manuals -=============== - -The preferred document format for the GNU system is the Texinfo -formatting language. Every GNU package should (ideally) have -documentation in Texinfo both for reference and for learners. Texinfo -makes it possible to produce a good quality formatted book, using TeX, -and to generate an Info file. It is also possible to generate HTML -output from Texinfo source. See the Texinfo manual, either the -hardcopy, or the on-line version available through 'info' or the Emacs -Info subsystem ('C-h i'). - - Nowadays some other formats such as Docbook and Sgmltexi can be -converted automatically into Texinfo. It is ok to produce the Texinfo -documentation by conversion this way, as long as it gives good results. - - Make sure your manual is clear to a reader who knows nothing about -the topic and reads it straight through. This means covering basic -topics at the beginning, and advanced topics only later. This also -means defining every specialized term when it is first used. - - Programmers tend to carry over the structure of the program as the -structure for its documentation. But this structure is not necessarily -good for explaining how to use the program; it may be irrelevant and -confusing for a user. - - Instead, the right way to structure documentation is according to the -concepts and questions that a user will have in mind when reading it. -This principle applies at every level, from the lowest (ordering -sentences in a paragraph) to the highest (ordering of chapter topics -within the manual). Sometimes this structure of ideas matches the -structure of the implementation of the software being documented--but -often they are different. An important part of learning to write good -documentation is to learn to notice when you have unthinkingly -structured the documentation like the implementation, stop yourself, and -look for better alternatives. - - For example, each program in the GNU system probably ought to be -documented in one manual; but this does not mean each program should -have its own manual. That would be following the structure of the -implementation, rather than the structure that helps the user -understand. - - Instead, each manual should cover a coherent _topic_. For example, -instead of a manual for 'diff' and a manual for 'diff3', we have one -manual for "comparison of files" which covers both of those programs, as -well as 'cmp'. By documenting these programs together, we can make the -whole subject clearer. - - The manual which discusses a program should certainly document all of -the program's command-line options and all of its commands. It should -give examples of their use. But don't organize the manual as a list of -features. Instead, organize it logically, by subtopics. Address the -questions that a user will ask when thinking about the job that the -program does. Don't just tell the reader what each feature can do--say -what jobs it is good for, and show how to use it for those jobs. -Explain what is recommended usage, and what kinds of usage users should -avoid. - - In general, a GNU manual should serve both as tutorial and reference. -It should be set up for convenient access to each topic through Info, -and for reading straight through (appendixes aside). A GNU manual -should give a good introduction to a beginner reading through from the -start, and should also provide all the details that hackers want. The -Bison manual is a good example of this--please take a look at it to see -what we mean. - - That is not as hard as it first sounds. Arrange each chapter as a -logical breakdown of its topic, but order the sections, and write their -text, so that reading the chapter straight through makes sense. Do -likewise when structuring the book into chapters, and when structuring a -section into paragraphs. The watchword is, _at each point, address the -most fundamental and important issue raised by the preceding text._ - - If necessary, add extra chapters at the beginning of the manual which -are purely tutorial and cover the basics of the subject. These provide -the framework for a beginner to understand the rest of the manual. The -Bison manual provides a good example of how to do this. - - To serve as a reference, a manual should have an Index that list all -the functions, variables, options, and important concepts that are part -of the program. One combined Index should do for a short manual, but -sometimes for a complex package it is better to use multiple indices. -The Texinfo manual includes advice on preparing good index entries, see -*note Making Index Entries: (texinfo)Index Entries, and see *note -Defining the Entries of an Index: (texinfo)Indexing Commands. - - Don't use Unix man pages as a model for how to write GNU -documentation; most of them are terse, badly structured, and give -inadequate explanation of the underlying concepts. (There are, of -course, some exceptions.) Also, Unix man pages use a particular format -which is different from what we use in GNU manuals. - - Please include an email address in the manual for where to report -bugs _in the text of the manual_. - - Please do not use the term "pathname" that is used in Unix -documentation; use "file name" (two words) instead. We use the term -"path" only for search paths, which are lists of directory names. - - Please do not use the term "illegal" to refer to erroneous input to a -computer program. Please use "invalid" for this, and reserve the term -"illegal" for activities prohibited by law. - - Please do not write '()' after a function name just to indicate it is -a function. 'foo ()' is not a function, it is a function call with no -arguments. - - -File: standards.info, Node: Doc Strings and Manuals, Next: Manual Structure Details, Prev: GNU Manuals, Up: Documentation - -6.2 Doc Strings and Manuals -=========================== - -Some programming systems, such as Emacs, provide a documentation string -for each function, command or variable. You may be tempted to write a -reference manual by compiling the documentation strings and writing a -little additional text to go around them--but you must not do it. That -approach is a fundamental mistake. The text of well-written -documentation strings will be entirely wrong for a manual. - - A documentation string needs to stand alone--when it appears on the -screen, there will be no other text to introduce or explain it. -Meanwhile, it can be rather informal in style. - - The text describing a function or variable in a manual must not stand -alone; it appears in the context of a section or subsection. Other text -at the beginning of the section should explain some of the concepts, and -should often make some general points that apply to several functions or -variables. The previous descriptions of functions and variables in the -section will also have given information about the topic. A description -written to stand alone would repeat some of that information; this -redundancy looks bad. Meanwhile, the informality that is acceptable in -a documentation string is totally unacceptable in a manual. - - The only good way to use documentation strings in writing a good -manual is to use them as a source of information for writing good text. - - -File: standards.info, Node: Manual Structure Details, Next: License for Manuals, Prev: Doc Strings and Manuals, Up: Documentation - -6.3 Manual Structure Details -============================ - -The title page of the manual should state the version of the programs or -packages documented in the manual. The Top node of the manual should -also contain this information. If the manual is changing more -frequently than or independent of the program, also state a version -number for the manual in both of these places. - - Each program documented in the manual should have a node named -'PROGRAM Invocation' or 'Invoking PROGRAM'. This node (together with -its subnodes, if any) should describe the program's command line -arguments and how to run it (the sort of information people would look -for in a man page). Start with an '@example' containing a template for -all the options and arguments that the program uses. - - Alternatively, put a menu item in some menu whose item name fits one -of the above patterns. This identifies the node which that item points -to as the node for this purpose, regardless of the node's actual name. - - The '--usage' feature of the Info reader looks for such a node or -menu item in order to find the relevant text, so it is essential for -every Texinfo file to have one. - - If one manual describes several programs, it should have such a node -for each program described in the manual. - - -File: standards.info, Node: License for Manuals, Next: Manual Credits, Prev: Manual Structure Details, Up: Documentation - -6.4 License for Manuals -======================= - -Please use the GNU Free Documentation License for all GNU manuals that -are more than a few pages long. Likewise for a collection of short -documents--you only need one copy of the GNU FDL for the whole -collection. For a single short document, you can use a very permissive -non-copyleft license, to avoid taking up space with a long license. - - See for more explanation -of how to employ the GFDL. - - Note that it is not obligatory to include a copy of the GNU GPL or -GNU LGPL in a manual whose license is neither the GPL nor the LGPL. It -can be a good idea to include the program's license in a large manual; -in a short manual, whose size would be increased considerably by -including the program's license, it is probably better not to include -it. - - -File: standards.info, Node: Manual Credits, Next: Printed Manuals, Prev: License for Manuals, Up: Documentation - -6.5 Manual Credits -================== - -Please credit the principal human writers of the manual as the authors, -on the title page of the manual. If a company sponsored the work, thank -the company in a suitable place in the manual, but do not cite the -company as an author. - - -File: standards.info, Node: Printed Manuals, Next: NEWS File, Prev: Manual Credits, Up: Documentation - -6.6 Printed Manuals -=================== - -The FSF publishes some GNU manuals in printed form. To encourage sales -of these manuals, the on-line versions of the manual should mention at -the very start that the printed manual is available and should point at -information for getting it--for instance, with a link to the page -. This should not be included in -the printed manual, though, because there it is redundant. - - It is also useful to explain in the on-line forms of the manual how -the user can print out the manual from the sources. - - -File: standards.info, Node: NEWS File, Next: Change Logs, Prev: Printed Manuals, Up: Documentation - -6.7 The NEWS File -================= - -In addition to its manual, the package should have a file named 'NEWS' -which contains a list of user-visible changes worth mentioning. In each -new release, add items to the front of the file and identify the version -they pertain to. Don't discard old items; leave them in the file after -the newer items. This way, a user upgrading from any previous version -can see what is new. - - If the 'NEWS' file gets very long, move some of the older items into -a file named 'ONEWS' and put a note at the end referring the user to -that file. - - -File: standards.info, Node: Change Logs, Next: Man Pages, Prev: NEWS File, Up: Documentation - -6.8 Change Logs -=============== - -Keep a change log to describe all the changes made to program source -files. The purpose of this is so that people investigating bugs in the -future will know about the changes that might have introduced the bug. -Often a new bug can be found by looking at what was recently changed. -More importantly, change logs can help you eliminate conceptual -inconsistencies between different parts of a program, by giving you a -history of how the conflicting concepts arose and who they came from. - -* Menu: - -* Change Log Concepts:: -* Style of Change Logs:: -* Simple Changes:: -* Conditional Changes:: -* Indicating the Part Changed:: - - -File: standards.info, Node: Change Log Concepts, Next: Style of Change Logs, Up: Change Logs - -6.8.1 Change Log Concepts -------------------------- - -You can think of the change log as a conceptual "undo list" which -explains how earlier versions were different from the current version. -People can see the current version; they don't need the change log to -tell them what is in it. What they want from a change log is a clear -explanation of how the earlier version differed. - - The change log file is normally called 'ChangeLog' and covers an -entire directory. Each directory can have its own change log, or a -directory can use the change log of its parent directory--it's up to -you. - - Another alternative is to record change log information with a -version control system such as RCS or CVS. This can be converted -automatically to a 'ChangeLog' file using 'rcs2log'; in Emacs, the -command 'C-x v a' ('vc-update-change-log') does the job. - - There's no need to describe the full purpose of the changes or how -they work together. However, sometimes it is useful to write one line -to describe the overall purpose of a change or a batch of changes. If -you think that a change calls for explanation, you're probably right. -Please do explain it--but please put the full explanation in comments in -the code, where people will see it whenever they see the code. For -example, "New function" is enough for the change log when you add a -function, because there should be a comment before the function -definition to explain what it does. - - In the past, we recommended not mentioning changes in non-software -files (manuals, help files, etc.) in change logs. However, we've been -advised that it is a good idea to include them, for the sake of -copyright records. - - The easiest way to add an entry to 'ChangeLog' is with the Emacs -command 'M-x add-change-log-entry'. An entry should have an asterisk, -the name of the changed file, and then in parentheses the name of the -changed functions, variables or whatever, followed by a colon. Then -describe the changes you made to that function or variable. - - -File: standards.info, Node: Style of Change Logs, Next: Simple Changes, Prev: Change Log Concepts, Up: Change Logs - -6.8.2 Style of Change Logs --------------------------- - -Here are some simple examples of change log entries, starting with the -header line that says who made the change and when it was installed, -followed by descriptions of specific changes. (These examples are drawn -from Emacs and GCC.) - - 1998-08-17 Richard Stallman - - * register.el (insert-register): Return nil. - (jump-to-register): Likewise. - - * sort.el (sort-subr): Return nil. - - * tex-mode.el (tex-bibtex-file, tex-file, tex-region): - Restart the tex shell if process is gone or stopped. - (tex-shell-running): New function. - - * expr.c (store_one_arg): Round size up for move_block_to_reg. - (expand_call): Round up when emitting USE insns. - * stmt.c (assign_parms): Round size up for move_block_from_reg. - - It's important to name the changed function or variable in full. -Don't abbreviate function or variable names, and don't combine them. -Subsequent maintainers will often search for a function name to find all -the change log entries that pertain to it; if you abbreviate the name, -they won't find it when they search. - - For example, some people are tempted to abbreviate groups of function -names by writing '* register.el ({insert,jump-to}-register)'; this is -not a good idea, since searching for 'jump-to-register' or -'insert-register' would not find that entry. - - Separate unrelated change log entries with blank lines. When two -entries represent parts of the same change, so that they work together, -then don't put blank lines between them. Then you can omit the file -name and the asterisk when successive entries are in the same file. - - Break long lists of function names by closing continued lines with -')', rather than ',', and opening the continuation with '(' as in this -example: - - * keyboard.c (menu_bar_items, tool_bar_items) - (Fexecute_extended_command): Deal with `keymap' property. - - When you install someone else's changes, put the contributor's name -in the change log entry rather than in the text of the entry. In other -words, write this: - - 2002-07-14 John Doe - - * sewing.c: Make it sew. - -rather than this: - - 2002-07-14 Usual Maintainer - - * sewing.c: Make it sew. Patch by jdoe@gnu.org. - - As for the date, that should be the date you applied the change. - - -File: standards.info, Node: Simple Changes, Next: Conditional Changes, Prev: Style of Change Logs, Up: Change Logs - -6.8.3 Simple Changes --------------------- - -Certain simple kinds of changes don't need much detail in the change -log. - - When you change the calling sequence of a function in a simple -fashion, and you change all the callers of the function to use the new -calling sequence, there is no need to make individual entries for all -the callers that you changed. Just write in the entry for the function -being called, "All callers changed"--like this: - - * keyboard.c (Fcommand_execute): New arg SPECIAL. - All callers changed. - - When you change just comments or doc strings, it is enough to write -an entry for the file, without mentioning the functions. Just "Doc -fixes" is enough for the change log. - - There's no technical need to make change log entries for -documentation files. This is because documentation is not susceptible -to bugs that are hard to fix. Documentation does not consist of parts -that must interact in a precisely engineered fashion. To correct an -error, you need not know the history of the erroneous passage; it is -enough to compare what the documentation says with the way the program -actually works. - - However, you should keep change logs for documentation files when the -project gets copyright assignments from its contributors, so as to make -the records of authorship more accurate. - - -File: standards.info, Node: Conditional Changes, Next: Indicating the Part Changed, Prev: Simple Changes, Up: Change Logs - -6.8.4 Conditional Changes -------------------------- - -C programs often contain compile-time '#if' conditionals. Many changes -are conditional; sometimes you add a new definition which is entirely -contained in a conditional. It is very useful to indicate in the change -log the conditions for which the change applies. - - Our convention for indicating conditional changes is to use square -brackets around the name of the condition. - - Here is a simple example, describing a change which is conditional -but does not have a function or entity name associated with it: - - * xterm.c [SOLARIS2]: Include string.h. - - Here is an entry describing a new definition which is entirely -conditional. This new definition for the macro 'FRAME_WINDOW_P' is used -only when 'HAVE_X_WINDOWS' is defined: - - * frame.h [HAVE_X_WINDOWS] (FRAME_WINDOW_P): Macro defined. - - Here is an entry for a change within the function 'init_display', -whose definition as a whole is unconditional, but the changes themselves -are contained in a '#ifdef HAVE_LIBNCURSES' conditional: - - * dispnew.c (init_display) [HAVE_LIBNCURSES]: If X, call tgetent. - - Here is an entry for a change that takes affect only when a certain -macro is _not_ defined: - - (gethostname) [!HAVE_SOCKETS]: Replace with winsock version. - - -File: standards.info, Node: Indicating the Part Changed, Prev: Conditional Changes, Up: Change Logs - -6.8.5 Indicating the Part Changed ---------------------------------- - -Indicate the part of a function which changed by using angle brackets -enclosing an indication of what the changed part does. Here is an entry -for a change in the part of the function 'sh-while-getopts' that deals -with 'sh' commands: - - * progmodes/sh-script.el (sh-while-getopts) : Handle case that - user-specified option string is empty. - - -File: standards.info, Node: Man Pages, Next: Reading other Manuals, Prev: Change Logs, Up: Documentation - -6.9 Man Pages -============= - -In the GNU project, man pages are secondary. It is not necessary or -expected for every GNU program to have a man page, but some of them do. -It's your choice whether to include a man page in your program. - - When you make this decision, consider that supporting a man page -requires continual effort each time the program is changed. The time -you spend on the man page is time taken away from more useful work. - - For a simple program which changes little, updating the man page may -be a small job. Then there is little reason not to include a man page, -if you have one. - - For a large program that changes a great deal, updating a man page -may be a substantial burden. If a user offers to donate a man page, you -may find this gift costly to accept. It may be better to refuse the man -page unless the same person agrees to take full responsibility for -maintaining it--so that you can wash your hands of it entirely. If this -volunteer later ceases to do the job, then don't feel obliged to pick it -up yourself; it may be better to withdraw the man page from the -distribution until someone else agrees to update it. - - When a program changes only a little, you may feel that the -discrepancies are small enough that the man page remains useful without -updating. If so, put a prominent note near the beginning of the man -page explaining that you don't maintain it and that the Texinfo manual -is more authoritative. The note should say how to access the Texinfo -documentation. - - Be sure that man pages include a copyright statement and free -license. The simple all-permissive license is appropriate for simple -man pages (*note (maintain)License Notices for Other Files::). - - For long man pages, with enough explanation and documentation that -they can be considered true manuals, use the GFDL (*note License for -Manuals::). - - Finally, the GNU help2man program -() is one way to automate -generation of a man page, in this case from '--help' output. This is -sufficient in many cases. - - -File: standards.info, Node: Reading other Manuals, Prev: Man Pages, Up: Documentation - -6.10 Reading other Manuals -========================== - -There may be non-free books or documentation files that describe the -program you are documenting. - - It is ok to use these documents for reference, just as the author of -a new algebra textbook can read other books on algebra. A large portion -of any non-fiction book consists of facts, in this case facts about how -a certain program works, and these facts are necessarily the same for -everyone who writes about the subject. But be careful not to copy your -outline structure, wording, tables or examples from preexisting non-free -documentation. Copying from free documentation may be ok; please check -with the FSF about the individual case. - - -File: standards.info, Node: Managing Releases, Next: References, Prev: Documentation, Up: Top - -7 The Release Process -********************* - -Making a release is more than just bundling up your source files in a -tar file and putting it up for FTP. You should set up your software so -that it can be configured to run on a variety of systems. Your Makefile -should conform to the GNU standards described below, and your directory -layout should also conform to the standards discussed below. Doing so -makes it easy to include your package into the larger framework of all -GNU software. - -* Menu: - -* Configuration:: How configuration of GNU packages should work. -* Makefile Conventions:: Makefile conventions. -* Releases:: Making releases - - -File: standards.info, Node: Configuration, Next: Makefile Conventions, Up: Managing Releases - -7.1 How Configuration Should Work -================================= - -Each GNU distribution should come with a shell script named 'configure'. -This script is given arguments which describe the kind of machine and -system you want to compile the program for. The 'configure' script must -record the configuration options so that they affect compilation. - - The description here is the specification of the interface for the -'configure' script in GNU packages. Many packages implement it using -GNU Autoconf (*note Introduction: (autoconf)Top.) and/or GNU Automake -(*note Introduction: (automake)Top.), but you do not have to use these -tools. You can implement it any way you like; for instance, by making -'configure' be a wrapper around a completely different configuration -system. - - Another way for the 'configure' script to operate is to make a link -from a standard name such as 'config.h' to the proper configuration file -for the chosen system. If you use this technique, the distribution -should _not_ contain a file named 'config.h'. This is so that people -won't be able to build the program without configuring it first. - - Another thing that 'configure' can do is to edit the Makefile. If -you do this, the distribution should _not_ contain a file named -'Makefile'. Instead, it should include a file 'Makefile.in' which -contains the input used for editing. Once again, this is so that people -won't be able to build the program without configuring it first. - - If 'configure' does write the 'Makefile', then 'Makefile' should have -a target named 'Makefile' which causes 'configure' to be rerun, setting -up the same configuration that was set up last time. The files that -'configure' reads should be listed as dependencies of 'Makefile'. - - All the files which are output from the 'configure' script should -have comments at the beginning explaining that they were generated -automatically using 'configure'. This is so that users won't think of -trying to edit them by hand. - - The 'configure' script should write a file named 'config.status' -which describes which configuration options were specified when the -program was last configured. This file should be a shell script which, -if run, will recreate the same configuration. - - The 'configure' script should accept an option of the form -'--srcdir=DIRNAME' to specify the directory where sources are found (if -it is not the current directory). This makes it possible to build the -program in a separate directory, so that the actual source directory is -not modified. - - If the user does not specify '--srcdir', then 'configure' should -check both '.' and '..' to see if it can find the sources. If it finds -the sources in one of these places, it should use them from there. -Otherwise, it should report that it cannot find the sources, and should -exit with nonzero status. - - Usually the easy way to support '--srcdir' is by editing a definition -of 'VPATH' into the Makefile. Some rules may need to refer explicitly -to the specified source directory. To make this possible, 'configure' -can add to the Makefile a variable named 'srcdir' whose value is -precisely the specified directory. - - In addition, the 'configure' script should take options corresponding -to most of the standard directory variables (*note Directory -Variables::). Here is the list: - - --prefix --exec-prefix --bindir --sbindir --libexecdir --sysconfdir - --sharedstatedir --localstatedir --libdir --includedir --oldincludedir - --datarootdir --datadir --infodir --localedir --mandir --docdir - --htmldir --dvidir --pdfdir --psdir - - The 'configure' script should also take an argument which specifies -the type of system to build the program for. This argument should look -like this: - - CPU-COMPANY-SYSTEM - - For example, an Athlon-based GNU/Linux system might be -'i686-pc-linux-gnu'. - - The 'configure' script needs to be able to decode all plausible -alternatives for how to describe a machine. Thus, 'athlon-pc-gnu/linux' -would be a valid alias. There is a shell script called 'config.sub' -(http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD) -that you can use as a subroutine to validate system types and -canonicalize aliases. - - The 'configure' script should also take the option -'--build=BUILDTYPE', which should be equivalent to a plain BUILDTYPE -argument. For example, 'configure --build=i686-pc-linux-gnu' is -equivalent to 'configure i686-pc-linux-gnu'. When the build type is not -specified by an option or argument, the 'configure' script should -normally guess it using the shell script 'config.guess' -(http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD). - - Other options are permitted to specify in more detail the software or -hardware present on the machine, to include or exclude optional parts of -the package, or to adjust the name of some tools or arguments to them: - -'--enable-FEATURE[=PARAMETER]' - Configure the package to build and install an optional user-level - facility called FEATURE. This allows users to choose which - optional features to include. Giving an optional PARAMETER of 'no' - should omit FEATURE, if it is built by default. - - No '--enable' option should *ever* cause one feature to replace - another. No '--enable' option should ever substitute one useful - behavior for another useful behavior. The only proper use for - '--enable' is for questions of whether to build part of the program - or exclude it. - -'--with-PACKAGE' - The package PACKAGE will be installed, so configure this package to - work with PACKAGE. - - Possible values of PACKAGE include 'gnu-as' (or 'gas'), 'gnu-ld', - 'gnu-libc', 'gdb', 'x', and 'x-toolkit'. - - Do not use a '--with' option to specify the file name to use to - find certain files. That is outside the scope of what '--with' - options are for. - -'VARIABLE=VALUE' - Set the value of the variable VARIABLE to VALUE. This is used to - override the default values of commands or arguments in the build - process. For example, the user could issue 'configure CFLAGS=-g - CXXFLAGS=-g' to build with debugging information and without the - default optimization. - - Specifying variables as arguments to 'configure', like this: - ./configure CC=gcc - is preferable to setting them in environment variables: - CC=gcc ./configure - as it helps to recreate the same configuration later with - 'config.status'. However, both methods should be supported. - - All 'configure' scripts should accept all of the "detail" options and -the variable settings, whether or not they make any difference to the -particular package at hand. In particular, they should accept any -option that starts with '--with-' or '--enable-'. This is so users will -be able to configure an entire GNU source tree at once with a single set -of options. - - You will note that the categories '--with-' and '--enable-' are -narrow: they *do not* provide a place for any sort of option you might -think of. That is deliberate. We want to limit the possible -configuration options in GNU software. We do not want GNU programs to -have idiosyncratic configuration options. - - Packages that perform part of the compilation process may support -cross-compilation. In such a case, the host and target machines for the -program may be different. - - The 'configure' script should normally treat the specified type of -system as both the host and the target, thus producing a program which -works for the same type of machine that it runs on. - - To compile a program to run on a host type that differs from the -build type, use the configure option '--host=HOSTTYPE', where HOSTTYPE -uses the same syntax as BUILDTYPE. The host type normally defaults to -the build type. - - To configure a cross-compiler, cross-assembler, or what have you, you -should specify a target different from the host, using the configure -option '--target=TARGETTYPE'. The syntax for TARGETTYPE is the same as -for the host type. So the command would look like this: - - ./configure --host=HOSTTYPE --target=TARGETTYPE - - The target type normally defaults to the host type. Programs for -which cross-operation is not meaningful need not accept the '--target' -option, because configuring an entire operating system for -cross-operation is not a meaningful operation. - - Some programs have ways of configuring themselves automatically. If -your program is set up to do this, your 'configure' script can simply -ignore most of its arguments. - - -File: standards.info, Node: Makefile Conventions, Next: Releases, Prev: Configuration, Up: Managing Releases - -7.2 Makefile Conventions -======================== - -This node describes conventions for writing the Makefiles for GNU -programs. Using Automake will help you write a Makefile that follows -these conventions. - -* Menu: - -* Makefile Basics:: General conventions for Makefiles. -* Utilities in Makefiles:: Utilities to be used in Makefiles. -* Command Variables:: Variables for specifying commands. -* DESTDIR:: Supporting staged installs. -* Directory Variables:: Variables for installation directories. -* Standard Targets:: Standard targets for users. -* Install Command Categories:: Three categories of commands in the 'install' - rule: normal, pre-install and post-install. - - -File: standards.info, Node: Makefile Basics, Next: Utilities in Makefiles, Up: Makefile Conventions - -7.2.1 General Conventions for Makefiles ---------------------------------------- - -Every Makefile should contain this line: - - SHELL = /bin/sh - -to avoid trouble on systems where the 'SHELL' variable might be -inherited from the environment. (This is never a problem with GNU -'make'.) - - Different 'make' programs have incompatible suffix lists and implicit -rules, and this sometimes creates confusion or misbehavior. So it is a -good idea to set the suffix list explicitly using only the suffixes you -need in the particular Makefile, like this: - - .SUFFIXES: - .SUFFIXES: .c .o - -The first line clears out the suffix list, the second introduces all -suffixes which may be subject to implicit rules in this Makefile. - - Don't assume that '.' is in the path for command execution. When you -need to run programs that are a part of your package during the make, -please make sure that it uses './' if the program is built as part of -the make or '$(srcdir)/' if the file is an unchanging part of the source -code. Without one of these prefixes, the current search path is used. - - The distinction between './' (the "build directory") and '$(srcdir)/' -(the "source directory") is important because users can build in a -separate directory using the '--srcdir' option to 'configure'. A rule -of the form: - - foo.1 : foo.man sedscript - sed -e sedscript foo.man > foo.1 - -will fail when the build directory is not the source directory, because -'foo.man' and 'sedscript' are in the source directory. - - When using GNU 'make', relying on 'VPATH' to find the source file -will work in the case where there is a single dependency file, since the -'make' automatic variable '$<' will represent the source file wherever -it is. (Many versions of 'make' set '$<' only in implicit rules.) A -Makefile target like - - foo.o : bar.c - $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o - -should instead be written as - - foo.o : bar.c - $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@ - -in order to allow 'VPATH' to work correctly. When the target has -multiple dependencies, using an explicit '$(srcdir)' is the easiest way -to make the rule work well. For example, the target above for 'foo.1' -is best written as: - - foo.1 : foo.man sedscript - sed -e $(srcdir)/sedscript $(srcdir)/foo.man > $@ - - GNU distributions usually contain some files which are not source -files--for example, Info files, and the output from Autoconf, Automake, -Bison or Flex. Since these files normally appear in the source -directory, they should always appear in the source directory, not in the -build directory. So Makefile rules to update them should put the -updated files in the source directory. - - However, if a file does not appear in the distribution, then the -Makefile should not put it in the source directory, because building a -program in ordinary circumstances should not modify the source directory -in any way. - - Try to make the build and installation targets, at least (and all -their subtargets) work correctly with a parallel 'make'. - - -File: standards.info, Node: Utilities in Makefiles, Next: Command Variables, Prev: Makefile Basics, Up: Makefile Conventions - -7.2.2 Utilities in Makefiles ----------------------------- - -Write the Makefile commands (and any shell scripts, such as 'configure') -to run in 'sh', not in 'csh'. Don't use any special features of 'ksh' -or 'bash'. - - The 'configure' script and the Makefile rules for building and -installation should not use any utilities directly except these: - - cat cmp cp diff echo egrep expr false grep install-info - ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true - - The compression program 'gzip' can be used in the 'dist' rule. - - Stick to the generally supported options for these programs. For -example, don't use 'mkdir -p', convenient as it may be, because most -systems don't support it. - - It is a good idea to avoid creating symbolic links in makefiles, -since a few systems don't support them. - - The Makefile rules for building and installation can also use -compilers and related programs, but should do so via 'make' variables so -that the user can substitute alternatives. Here are some of the -programs we mean: - - ar bison cc flex install ld ldconfig lex - make makeinfo ranlib texi2dvi yacc - - Use the following 'make' variables to run those programs: - - $(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX) - $(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC) - - When you use 'ranlib' or 'ldconfig', you should make sure nothing bad -happens if the system does not have the program in question. Arrange to -ignore an error from that command, and print a message before the -command to tell the user that failure of this command does not mean a -problem. (The Autoconf 'AC_PROG_RANLIB' macro can help with this.) - - If you use symbolic links, you should implement a fallback for -systems that don't have symbolic links. - - Additional utilities that can be used via Make variables are: - - chgrp chmod chown mknod - - It is ok to use other utilities in Makefile portions (or scripts) -intended only for particular systems where you know those utilities -exist. - - -File: standards.info, Node: Command Variables, Next: DESTDIR, Prev: Utilities in Makefiles, Up: Makefile Conventions - -7.2.3 Variables for Specifying Commands ---------------------------------------- - -Makefiles should provide variables for overriding certain commands, -options, and so on. - - In particular, you should run most utility programs via variables. -Thus, if you use Bison, have a variable named 'BISON' whose default -value is set with 'BISON = bison', and refer to it with '$(BISON)' -whenever you need to use Bison. - - File management utilities such as 'ln', 'rm', 'mv', and so on, need -not be referred to through variables in this way, since users don't need -to replace them with other programs. - - Each program-name variable should come with an options variable that -is used to supply options to the program. Append 'FLAGS' to the -program-name variable name to get the options variable name--for -example, 'BISONFLAGS'. (The names 'CFLAGS' for the C compiler, 'YFLAGS' -for yacc, and 'LFLAGS' for lex, are exceptions to this rule, but we keep -them because they are standard.) Use 'CPPFLAGS' in any compilation -command that runs the preprocessor, and use 'LDFLAGS' in any compilation -command that does linking as well as in any direct use of 'ld'. - - If there are C compiler options that _must_ be used for proper -compilation of certain files, do not include them in 'CFLAGS'. Users -expect to be able to specify 'CFLAGS' freely themselves. Instead, -arrange to pass the necessary options to the C compiler independently of -'CFLAGS', by writing them explicitly in the compilation commands or by -defining an implicit rule, like this: - - CFLAGS = -g - ALL_CFLAGS = -I. $(CFLAGS) - .c.o: - $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $< - - Do include the '-g' option in 'CFLAGS', because that is not -_required_ for proper compilation. You can consider it a default that -is only recommended. If the package is set up so that it is compiled -with GCC by default, then you might as well include '-O' in the default -value of 'CFLAGS' as well. - - Put 'CFLAGS' last in the compilation command, after other variables -containing compiler options, so the user can use 'CFLAGS' to override -the others. - - 'CFLAGS' should be used in every invocation of the C compiler, both -those which do compilation and those which do linking. - - Every Makefile should define the variable 'INSTALL', which is the -basic command for installing a file into the system. - - Every Makefile should also define the variables 'INSTALL_PROGRAM' and -'INSTALL_DATA'. (The default for 'INSTALL_PROGRAM' should be -'$(INSTALL)'; the default for 'INSTALL_DATA' should be '${INSTALL} -m -644'.) Then it should use those variables as the commands for actual -installation, for executables and non-executables respectively. Minimal -use of these variables is as follows: - - $(INSTALL_PROGRAM) foo $(bindir)/foo - $(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a - - However, it is preferable to support a 'DESTDIR' prefix on the target -files, as explained in the next section. - -Always use a file name, not a directory name, as the second argument of -the installation commands. Use a separate command for each file to be -installed. - - -File: standards.info, Node: DESTDIR, Next: Directory Variables, Prev: Command Variables, Up: Makefile Conventions - -7.2.4 'DESTDIR': support for staged installs --------------------------------------------- - -'DESTDIR' is a variable prepended to each installed target file, like -this: - - $(INSTALL_PROGRAM) foo $(DESTDIR)$(bindir)/foo - $(INSTALL_DATA) libfoo.a $(DESTDIR)$(libdir)/libfoo.a - - The 'DESTDIR' variable is specified by the user on the 'make' command -line. For example: - - make DESTDIR=/tmp/stage install - -'DESTDIR' should be supported only in the 'install*' and 'uninstall*' -targets, as those are the only targets where it is useful. - - If your installation step would normally install '/usr/local/bin/foo' -and '/usr/local/lib/libfoo.a', then an installation invoked as in the -example above would install '/tmp/stage/usr/local/bin/foo' and -'/tmp/stage/usr/local/lib/libfoo.a' instead. - - Prepending the variable 'DESTDIR' to each target in this way provides -for "staged installs", where the installed files are not placed directly -into their expected location but are instead copied into a temporary -location ('DESTDIR'). However, installed files maintain their relative -directory structure and any embedded file names will not be modified. - - You should not set the value of 'DESTDIR' in your 'Makefile' at all; -then the files are installed into their expected locations by default. -Also, specifying 'DESTDIR' should not change the operation of the -software in any way, so its value should not be included in any file -contents. - - 'DESTDIR' support is commonly used in package creation. It is also -helpful to users who want to understand what a given package will -install where, and to allow users who don't normally have permissions to -install into protected areas to build and install before gaining those -permissions. Finally, it can be useful with tools such as 'stow', where -code is installed in one place but made to appear to be installed -somewhere else using symbolic links or special mount operations. So, we -strongly recommend GNU packages support 'DESTDIR', though it is not an -absolute requirement. - - -File: standards.info, Node: Directory Variables, Next: Standard Targets, Prev: DESTDIR, Up: Makefile Conventions - -7.2.5 Variables for Installation Directories --------------------------------------------- - -Installation directories should always be named by variables, so it is -easy to install in a nonstandard place. The standard names for these -variables and the values they should have in GNU packages are described -below. They are based on a standard file system layout; variants of it -are used in GNU/Linux and other modern operating systems. - - Installers are expected to override these values when calling 'make' -(e.g., 'make prefix=/usr install' or 'configure' (e.g., 'configure ---prefix=/usr'). GNU packages should not try to guess which value -should be appropriate for these variables on the system they are being -installed onto: use the default settings specified here so that all GNU -packages behave identically, allowing the installer to achieve any -desired layout. - - These first two variables set the root for the installation. All the -other installation directories should be subdirectories of one of these -two, and nothing should be directly installed into these two -directories. - -'prefix' - A prefix used in constructing the default values of the variables - listed below. The default value of 'prefix' should be - '/usr/local'. When building the complete GNU system, the prefix - will be empty and '/usr' will be a symbolic link to '/'. (If you - are using Autoconf, write it as '@prefix@'.) - - Running 'make install' with a different value of 'prefix' from the - one used to build the program should _not_ recompile the program. - -'exec_prefix' - A prefix used in constructing the default values of some of the - variables listed below. The default value of 'exec_prefix' should - be '$(prefix)'. (If you are using Autoconf, write it as - '@exec_prefix@'.) - - Generally, '$(exec_prefix)' is used for directories that contain - machine-specific files (such as executables and subroutine - libraries), while '$(prefix)' is used directly for other - directories. - - Running 'make install' with a different value of 'exec_prefix' from - the one used to build the program should _not_ recompile the - program. - - Executable programs are installed in one of the following -directories. - -'bindir' - The directory for installing executable programs that users can - run. This should normally be '/usr/local/bin', but write it as - '$(exec_prefix)/bin'. (If you are using Autoconf, write it as - '@bindir@'.) - -'sbindir' - The directory for installing executable programs that can be run - from the shell, but are only generally useful to system - administrators. This should normally be '/usr/local/sbin', but - write it as '$(exec_prefix)/sbin'. (If you are using Autoconf, - write it as '@sbindir@'.) - -'libexecdir' - The directory for installing executable programs to be run by other - programs rather than by users. This directory should normally be - '/usr/local/libexec', but write it as '$(exec_prefix)/libexec'. - (If you are using Autoconf, write it as '@libexecdir@'.) - - The definition of 'libexecdir' is the same for all packages, so you - should install your data in a subdirectory thereof. Most packages - install their data under '$(libexecdir)/PACKAGE-NAME/', possibly - within additional subdirectories thereof, such as - '$(libexecdir)/PACKAGE-NAME/MACHINE/VERSION'. - - Data files used by the program during its execution are divided into -categories in two ways. - - * Some files are normally modified by programs; others are never - normally modified (though users may edit some of these). - - * Some files are architecture-independent and can be shared by all - machines at a site; some are architecture-dependent and can be - shared only by machines of the same kind and operating system; - others may never be shared between two machines. - - This makes for six different possibilities. However, we want to -discourage the use of architecture-dependent files, aside from object -files and libraries. It is much cleaner to make other data files -architecture-independent, and it is generally not hard. - - Here are the variables Makefiles should use to specify directories to -put these various kinds of files in: - -'datarootdir' - The root of the directory tree for read-only - architecture-independent data files. This should normally be - '/usr/local/share', but write it as '$(prefix)/share'. (If you are - using Autoconf, write it as '@datarootdir@'.) 'datadir''s default - value is based on this variable; so are 'infodir', 'mandir', and - others. - -'datadir' - The directory for installing idiosyncratic read-only - architecture-independent data files for this program. This is - usually the same place as 'datarootdir', but we use the two - separate variables so that you can move these program-specific - files without altering the location for Info files, man pages, etc. - - This should normally be '/usr/local/share', but write it as - '$(datarootdir)'. (If you are using Autoconf, write it as - '@datadir@'.) - - The definition of 'datadir' is the same for all packages, so you - should install your data in a subdirectory thereof. Most packages - install their data under '$(datadir)/PACKAGE-NAME/'. - -'sysconfdir' - The directory for installing read-only data files that pertain to a - single machine-that is to say, files for configuring a host. - Mailer and network configuration files, '/etc/passwd', and so forth - belong here. All the files in this directory should be ordinary - ASCII text files. This directory should normally be - '/usr/local/etc', but write it as '$(prefix)/etc'. (If you are - using Autoconf, write it as '@sysconfdir@'.) - - Do not install executables here in this directory (they probably - belong in '$(libexecdir)' or '$(sbindir)'). Also do not install - files that are modified in the normal course of their use (programs - whose purpose is to change the configuration of the system - excluded). Those probably belong in '$(localstatedir)'. - -'sharedstatedir' - The directory for installing architecture-independent data files - which the programs modify while they run. This should normally be - '/usr/local/com', but write it as '$(prefix)/com'. (If you are - using Autoconf, write it as '@sharedstatedir@'.) - -'localstatedir' - The directory for installing data files which the programs modify - while they run, and that pertain to one specific machine. Users - should never need to modify files in this directory to configure - the package's operation; put such configuration information in - separate files that go in '$(datadir)' or '$(sysconfdir)'. - '$(localstatedir)' should normally be '/usr/local/var', but write - it as '$(prefix)/var'. (If you are using Autoconf, write it as - '@localstatedir@'.) - - These variables specify the directory for installing certain specific -types of files, if your program has them. Every GNU package should have -Info files, so every program needs 'infodir', but not all need 'libdir' -or 'lispdir'. - -'includedir' - The directory for installing header files to be included by user - programs with the C '#include' preprocessor directive. This should - normally be '/usr/local/include', but write it as - '$(prefix)/include'. (If you are using Autoconf, write it as - '@includedir@'.) - - Most compilers other than GCC do not look for header files in - directory '/usr/local/include'. So installing the header files - this way is only useful with GCC. Sometimes this is not a problem - because some libraries are only really intended to work with GCC. - But some libraries are intended to work with other compilers. They - should install their header files in two places, one specified by - 'includedir' and one specified by 'oldincludedir'. - -'oldincludedir' - The directory for installing '#include' header files for use with - compilers other than GCC. This should normally be '/usr/include'. - (If you are using Autoconf, you can write it as '@oldincludedir@'.) - - The Makefile commands should check whether the value of - 'oldincludedir' is empty. If it is, they should not try to use it; - they should cancel the second installation of the header files. - - A package should not replace an existing header in this directory - unless the header came from the same package. Thus, if your Foo - package provides a header file 'foo.h', then it should install the - header file in the 'oldincludedir' directory if either (1) there is - no 'foo.h' there or (2) the 'foo.h' that exists came from the Foo - package. - - To tell whether 'foo.h' came from the Foo package, put a magic - string in the file--part of a comment--and 'grep' for that string. - -'docdir' - The directory for installing documentation files (other than Info) - for this package. By default, it should be - '/usr/local/share/doc/YOURPKG', but it should be written as - '$(datarootdir)/doc/YOURPKG'. (If you are using Autoconf, write it - as '@docdir@'.) The YOURPKG subdirectory, which may include a - version number, prevents collisions among files with common names, - such as 'README'. - -'infodir' - The directory for installing the Info files for this package. By - default, it should be '/usr/local/share/info', but it should be - written as '$(datarootdir)/info'. (If you are using Autoconf, - write it as '@infodir@'.) 'infodir' is separate from 'docdir' for - compatibility with existing practice. - -'htmldir' -'dvidir' -'pdfdir' -'psdir' - Directories for installing documentation files in the particular - format. They should all be set to '$(docdir)' by default. (If you - are using Autoconf, write them as '@htmldir@', '@dvidir@', etc.) - Packages which supply several translations of their documentation - should install them in '$(htmldir)/'LL, '$(pdfdir)/'LL, etc. where - LL is a locale abbreviation such as 'en' or 'pt_BR'. - -'libdir' - The directory for object files and libraries of object code. Do - not install executables here, they probably ought to go in - '$(libexecdir)' instead. The value of 'libdir' should normally be - '/usr/local/lib', but write it as '$(exec_prefix)/lib'. (If you - are using Autoconf, write it as '@libdir@'.) - -'lispdir' - The directory for installing any Emacs Lisp files in this package. - By default, it should be '/usr/local/share/emacs/site-lisp', but it - should be written as '$(datarootdir)/emacs/site-lisp'. - - If you are using Autoconf, write the default as '@lispdir@'. In - order to make '@lispdir@' work, you need the following lines in - your 'configure.in' file: - - lispdir='${datarootdir}/emacs/site-lisp' - AC_SUBST(lispdir) - -'localedir' - The directory for installing locale-specific message catalogs for - this package. By default, it should be '/usr/local/share/locale', - but it should be written as '$(datarootdir)/locale'. (If you are - using Autoconf, write it as '@localedir@'.) This directory usually - has a subdirectory per locale. - - Unix-style man pages are installed in one of the following: - -'mandir' - The top-level directory for installing the man pages (if any) for - this package. It will normally be '/usr/local/share/man', but you - should write it as '$(datarootdir)/man'. (If you are using - Autoconf, write it as '@mandir@'.) - -'man1dir' - The directory for installing section 1 man pages. Write it as - '$(mandir)/man1'. -'man2dir' - The directory for installing section 2 man pages. Write it as - '$(mandir)/man2' -'...' - - *Don't make the primary documentation for any GNU software be a man - page. Write a manual in Texinfo instead. Man pages are just for - the sake of people running GNU software on Unix, which is a - secondary application only.* - -'manext' - The file name extension for the installed man page. This should - contain a period followed by the appropriate digit; it should - normally be '.1'. - -'man1ext' - The file name extension for installed section 1 man pages. -'man2ext' - The file name extension for installed section 2 man pages. -'...' - Use these names instead of 'manext' if the package needs to install - man pages in more than one section of the manual. - - And finally, you should set the following variable: - -'srcdir' - The directory for the sources being compiled. The value of this - variable is normally inserted by the 'configure' shell script. (If - you are using Autoconf, use 'srcdir = @srcdir@'.) - - For example: - - # Common prefix for installation directories. - # NOTE: This directory must exist when you start the install. - prefix = /usr/local - datarootdir = $(prefix)/share - datadir = $(datarootdir) - exec_prefix = $(prefix) - # Where to put the executable for the command `gcc'. - bindir = $(exec_prefix)/bin - # Where to put the directories used by the compiler. - libexecdir = $(exec_prefix)/libexec - # Where to put the Info files. - infodir = $(datarootdir)/info - - If your program installs a large number of files into one of the -standard user-specified directories, it might be useful to group them -into a subdirectory particular to that program. If you do this, you -should write the 'install' rule to create these subdirectories. - - Do not expect the user to include the subdirectory name in the value -of any of the variables listed above. The idea of having a uniform set -of variable names for installation directories is to enable the user to -specify the exact same values for several different GNU packages. In -order for this to be useful, all the packages must be designed so that -they will work sensibly when the user does so. - - At times, not all of these variables may be implemented in the -current release of Autoconf and/or Automake; but as of Autoconf 2.60, we -believe all of them are. When any are missing, the descriptions here -serve as specifications for what Autoconf will implement. As a -programmer, you can either use a development version of Autoconf or -avoid using these variables until a stable release is made which -supports them. - - -File: standards.info, Node: Standard Targets, Next: Install Command Categories, Prev: Directory Variables, Up: Makefile Conventions - -7.2.6 Standard Targets for Users --------------------------------- - -All GNU programs should have the following targets in their Makefiles: - -'all' - Compile the entire program. This should be the default target. - This target need not rebuild any documentation files; Info files - should normally be included in the distribution, and DVI (and other - documentation format) files should be made only when explicitly - asked for. - - By default, the Make rules should compile and link with '-g', so - that executable programs have debugging symbols. Users who don't - mind being helpless can strip the executables later if they wish. - -'install' - Compile the program and copy the executables, libraries, and so on - to the file names where they should reside for actual use. If - there is a simple test to verify that a program is properly - installed, this target should run that test. - - Do not strip executables when installing them. Devil-may-care - users can use the 'install-strip' target to do that. - - If possible, write the 'install' target rule so that it does not - modify anything in the directory where the program was built, - provided 'make all' has just been done. This is convenient for - building the program under one user name and installing it under - another. - - The commands should create all the directories in which files are - to be installed, if they don't already exist. This includes the - directories specified as the values of the variables 'prefix' and - 'exec_prefix', as well as all subdirectories that are needed. One - way to do this is by means of an 'installdirs' target as described - below. - - Use '-' before any command for installing a man page, so that - 'make' will ignore any errors. This is in case there are systems - that don't have the Unix man page documentation system installed. - - The way to install Info files is to copy them into '$(infodir)' - with '$(INSTALL_DATA)' (*note Command Variables::), and then run - the 'install-info' program if it is present. 'install-info' is a - program that edits the Info 'dir' file to add or update the menu - entry for the given Info file; it is part of the Texinfo package. - Here is a sample rule to install an Info file: - - $(DESTDIR)$(infodir)/foo.info: foo.info - $(POST_INSTALL) - # There may be a newer info file in . than in srcdir. - -if test -f foo.info; then d=.; \ - else d=$(srcdir); fi; \ - $(INSTALL_DATA) $$d/foo.info $(DESTDIR)$@; \ - # Run install-info only if it exists. - # Use `if' instead of just prepending `-' to the - # line so we notice real errors from install-info. - # We use `$(SHELL) -c' because some shells do not - # fail gracefully when there is an unknown command. - if $(SHELL) -c 'install-info --version' \ - >/dev/null 2>&1; then \ - install-info --dir-file=$(DESTDIR)$(infodir)/dir \ - $(DESTDIR)$(infodir)/foo.info; \ - else true; fi - - When writing the 'install' target, you must classify all the - commands into three categories: normal ones, "pre-installation" - commands and "post-installation" commands. *Note Install Command - Categories::. - -'install-html' -'install-dvi' -'install-pdf' -'install-ps' - These targets install documentation in formats other than Info; - they're intended to be called explicitly by the person installing - the package, if that format is desired. GNU prefers Info files, so - these must be installed by the 'install' target. - - When you have many documentation files to install, we recommend - that you avoid collisions and clutter by arranging for these - targets to install in subdirectories of the appropriate - installation directory, such as 'htmldir'. As one example, if your - package has multiple manuals, and you wish to install HTML - documentation with many files (such as the "split" mode output by - 'makeinfo --html'), you'll certainly want to use subdirectories, or - two nodes with the same name in different manuals will overwrite - each other. - - Please make these 'install-FORMAT' targets invoke the commands for - the FORMAT target, for example, by making FORMAT a dependency. - -'uninstall' - Delete all the installed files--the copies that the 'install' and - 'install-*' targets create. - - This rule should not modify the directories where compilation is - done, only the directories where files are installed. - - The uninstallation commands are divided into three categories, just - like the installation commands. *Note Install Command - Categories::. - -'install-strip' - Like 'install', but strip the executable files while installing - them. In simple cases, this target can use the 'install' target in - a simple way: - - install-strip: - $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' \ - install - - But if the package installs scripts as well as real executables, - the 'install-strip' target can't just refer to the 'install' - target; it has to strip the executables but not the scripts. - - 'install-strip' should not strip the executables in the build - directory which are being copied for installation. It should only - strip the copies that are installed. - - Normally we do not recommend stripping an executable unless you are - sure the program has no bugs. However, it can be reasonable to - install a stripped executable for actual execution while saving the - unstripped executable elsewhere in case there is a bug. - -'clean' - - Delete all files in the current directory that are normally created - by building the program. Also delete files in other directories if - they are created by this makefile. However, don't delete the files - that record the configuration. Also preserve files that could be - made by building, but normally aren't because the distribution - comes with them. There is no need to delete parent directories - that were created with 'mkdir -p', since they could have existed - anyway. - - Delete '.dvi' files here if they are not part of the distribution. - -'distclean' - Delete all files in the current directory (or created by this - makefile) that are created by configuring or building the program. - If you have unpacked the source and built the program without - creating any other files, 'make distclean' should leave only the - files that were in the distribution. However, there is no need to - delete parent directories that were created with 'mkdir -p', since - they could have existed anyway. - -'mostlyclean' - Like 'clean', but may refrain from deleting a few files that people - normally don't want to recompile. For example, the 'mostlyclean' - target for GCC does not delete 'libgcc.a', because recompiling it - is rarely necessary and takes a lot of time. - -'maintainer-clean' - Delete almost everything that can be reconstructed with this - Makefile. This typically includes everything deleted by - 'distclean', plus more: C source files produced by Bison, tags - tables, Info files, and so on. - - The reason we say "almost everything" is that running the command - 'make maintainer-clean' should not delete 'configure' even if - 'configure' can be remade using a rule in the Makefile. More - generally, 'make maintainer-clean' should not delete anything that - needs to exist in order to run 'configure' and then begin to build - the program. Also, there is no need to delete parent directories - that were created with 'mkdir -p', since they could have existed - anyway. These are the only exceptions; 'maintainer-clean' should - delete everything else that can be rebuilt. - - The 'maintainer-clean' target is intended to be used by a - maintainer of the package, not by ordinary users. You may need - special tools to reconstruct some of the files that 'make - maintainer-clean' deletes. Since these files are normally included - in the distribution, we don't take care to make them easy to - reconstruct. If you find you need to unpack the full distribution - again, don't blame us. - - To help make users aware of this, the commands for the special - 'maintainer-clean' target should start with these two: - - @echo 'This command is intended for maintainers to use; it' - @echo 'deletes files that may need special tools to rebuild.' - -'TAGS' - Update a tags table for this program. - -'info' - Generate any Info files needed. The best way to write the rules is - as follows: - - info: foo.info - - foo.info: foo.texi chap1.texi chap2.texi - $(MAKEINFO) $(srcdir)/foo.texi - - You must define the variable 'MAKEINFO' in the Makefile. It should - run the 'makeinfo' program, which is part of the Texinfo - distribution. - - Normally a GNU distribution comes with Info files, and that means - the Info files are present in the source directory. Therefore, the - Make rule for an info file should update it in the source - directory. When users build the package, ordinarily Make will not - update the Info files because they will already be up to date. - -'dvi' -'html' -'pdf' -'ps' - Generate documentation files in the given format. These targets - should always exist, but any or all can be a no-op if the given - output format cannot be generated. These targets should not be - dependencies of the 'all' target; the user must manually invoke - them. - - Here's an example rule for generating DVI files from Texinfo: - - dvi: foo.dvi - - foo.dvi: foo.texi chap1.texi chap2.texi - $(TEXI2DVI) $(srcdir)/foo.texi - - You must define the variable 'TEXI2DVI' in the Makefile. It should - run the program 'texi2dvi', which is part of the Texinfo - distribution.(1) Alternatively, write just the dependencies, and - allow GNU 'make' to provide the command. - - Here's another example, this one for generating HTML from Texinfo: - - html: foo.html - - foo.html: foo.texi chap1.texi chap2.texi - $(TEXI2HTML) $(srcdir)/foo.texi - - Again, you would define the variable 'TEXI2HTML' in the Makefile; - for example, it might run 'makeinfo --no-split --html' ('makeinfo' - is part of the Texinfo distribution). - -'dist' - Create a distribution tar file for this program. The tar file - should be set up so that the file names in the tar file start with - a subdirectory name which is the name of the package it is a - distribution for. This name can include the version number. - - For example, the distribution tar file of GCC version 1.40 unpacks - into a subdirectory named 'gcc-1.40'. - - The easiest way to do this is to create a subdirectory - appropriately named, use 'ln' or 'cp' to install the proper files - in it, and then 'tar' that subdirectory. - - Compress the tar file with 'gzip'. For example, the actual - distribution file for GCC version 1.40 is called 'gcc-1.40.tar.gz'. - - The 'dist' target should explicitly depend on all non-source files - that are in the distribution, to make sure they are up to date in - the distribution. *Note Making Releases: Releases. - -'check' - Perform self-tests (if any). The user must build the program - before running the tests, but need not install the program; you - should write the self-tests so that they work when the program is - built but not installed. - - The following targets are suggested as conventional names, for -programs in which they are useful. - -'installcheck' - Perform installation tests (if any). The user must build and - install the program before running the tests. You should not - assume that '$(bindir)' is in the search path. - -'installdirs' - It's useful to add a target named 'installdirs' to create the - directories where files are installed, and their parent - directories. There is a script called 'mkinstalldirs' which is - convenient for this; you can find it in the Texinfo package. You - can use a rule like this: - - # Make sure all installation directories (e.g. $(bindir)) - # actually exist by making them if necessary. - installdirs: mkinstalldirs - $(srcdir)/mkinstalldirs $(bindir) $(datadir) \ - $(libdir) $(infodir) \ - $(mandir) - - or, if you wish to support 'DESTDIR', - - # Make sure all installation directories (e.g. $(bindir)) - # actually exist by making them if necessary. - installdirs: mkinstalldirs - $(srcdir)/mkinstalldirs \ - $(DESTDIR)$(bindir) $(DESTDIR)$(datadir) \ - $(DESTDIR)$(libdir) $(DESTDIR)$(infodir) \ - $(DESTDIR)$(mandir) - - This rule should not modify the directories where compilation is - done. It should do nothing but create installation directories. - - ---------- Footnotes ---------- - - (1) 'texi2dvi' uses TeX to do the real work of formatting. TeX is -not distributed with Texinfo. - - -File: standards.info, Node: Install Command Categories, Prev: Standard Targets, Up: Makefile Conventions - -7.2.7 Install Command Categories --------------------------------- - -When writing the 'install' target, you must classify all the commands -into three categories: normal ones, "pre-installation" commands and -"post-installation" commands. - - Normal commands move files into their proper places, and set their -modes. They may not alter any files except the ones that come entirely -from the package they belong to. - - Pre-installation and post-installation commands may alter other -files; in particular, they can edit global configuration files or data -bases. - - Pre-installation commands are typically executed before the normal -commands, and post-installation commands are typically run after the -normal commands. - - The most common use for a post-installation command is to run -'install-info'. This cannot be done with a normal command, since it -alters a file (the Info directory) which does not come entirely and -solely from the package being installed. It is a post-installation -command because it needs to be done after the normal command which -installs the package's Info files. - - Most programs don't need any pre-installation commands, but we have -the feature just in case it is needed. - - To classify the commands in the 'install' rule into these three -categories, insert "category lines" among them. A category line -specifies the category for the commands that follow. - - A category line consists of a tab and a reference to a special Make -variable, plus an optional comment at the end. There are three -variables you can use, one for each category; the variable name -specifies the category. Category lines are no-ops in ordinary execution -because these three Make variables are normally undefined (and you -_should not_ define them in the makefile). - - Here are the three possible category lines, each with a comment that -explains what it means: - - $(PRE_INSTALL) # Pre-install commands follow. - $(POST_INSTALL) # Post-install commands follow. - $(NORMAL_INSTALL) # Normal commands follow. - - If you don't use a category line at the beginning of the 'install' -rule, all the commands are classified as normal until the first category -line. If you don't use any category lines, all the commands are -classified as normal. - - These are the category lines for 'uninstall': - - $(PRE_UNINSTALL) # Pre-uninstall commands follow. - $(POST_UNINSTALL) # Post-uninstall commands follow. - $(NORMAL_UNINSTALL) # Normal commands follow. - - Typically, a pre-uninstall command would be used for deleting entries -from the Info directory. - - If the 'install' or 'uninstall' target has any dependencies which act -as subroutines of installation, then you should start _each_ -dependency's commands with a category line, and start the main target's -commands with a category line also. This way, you can ensure that each -command is placed in the right category regardless of which of the -dependencies actually run. - - Pre-installation and post-installation commands should not run any -programs except for these: - - [ basename bash cat chgrp chmod chown cmp cp dd diff echo - egrep expand expr false fgrep find getopt grep gunzip gzip - hostname install install-info kill ldconfig ln ls md5sum - mkdir mkfifo mknod mv printenv pwd rm rmdir sed sort tee - test touch true uname xargs yes - - The reason for distinguishing the commands in this way is for the -sake of making binary packages. Typically a binary package contains all -the executables and other files that need to be installed, and has its -own method of installing them--so it does not need to run the normal -installation commands. But installing the binary package does need to -execute the pre-installation and post-installation commands. - - Programs to build binary packages work by extracting the -pre-installation and post-installation commands. Here is one way of -extracting the pre-installation commands (the '-s' option to 'make' is -needed to silence messages about entering subdirectories): - - make -s -n install -o all \ - PRE_INSTALL=pre-install \ - POST_INSTALL=post-install \ - NORMAL_INSTALL=normal-install \ - | gawk -f pre-install.awk - -where the file 'pre-install.awk' could contain this: - - $0 ~ /^(normal-install|post-install)[ \t]*$/ {on = 0} - on {print $0} - $0 ~ /^pre-install[ \t]*$/ {on = 1} - - -File: standards.info, Node: Releases, Prev: Makefile Conventions, Up: Managing Releases - -7.3 Making Releases -=================== - -You should identify each release with a pair of version numbers, a major -version and a minor. We have no objection to using more than two -numbers, but it is very unlikely that you really need them. - - Package the distribution of 'Foo version 69.96' up in a gzipped tar -file with the name 'foo-69.96.tar.gz'. It should unpack into a -subdirectory named 'foo-69.96'. - - Building and installing the program should never modify any of the -files contained in the distribution. This means that all the files that -form part of the program in any way must be classified into "source -files" and "non-source files". Source files are written by humans and -never changed automatically; non-source files are produced from source -files by programs under the control of the Makefile. - - The distribution should contain a file named 'README' which gives the -name of the package, and a general description of what it does. It is -also good to explain the purpose of each of the first-level -subdirectories in the package, if there are any. The 'README' file -should either state the version number of the package, or refer to where -in the package it can be found. - - The 'README' file should refer to the file 'INSTALL', which should -contain an explanation of the installation procedure. - - The 'README' file should also refer to the file which contains the -copying conditions. The GNU GPL, if used, should be in a file called -'COPYING'. If the GNU LGPL is used, it should be in a file called -'COPYING.LESSER'. - - Naturally, all the source files must be in the distribution. It is -okay to include non-source files in the distribution, provided they are -up-to-date and machine-independent, so that building the distribution -normally will never modify them. We commonly include non-source files -produced by Bison, 'lex', TeX, and 'makeinfo'; this helps avoid -unnecessary dependencies between our distributions, so that users can -install whichever packages they want to install. - - Non-source files that might actually be modified by building and -installing the program should *never* be included in the distribution. -So if you do distribute non-source files, always make sure they are up -to date when you make a new distribution. - - Make sure that all the files in the distribution are world-readable, -and that directories are world-readable and world-searchable (octal mode -755). We used to recommend that all directories in the distribution -also be world-writable (octal mode 777), because ancient versions of -'tar' would otherwise not cope when extracting the archive as an -unprivileged user. That can easily lead to security issues when -creating the archive, however, so now we recommend against that. - - Don't include any symbolic links in the distribution itself. If the -tar file contains symbolic links, then people cannot even unpack it on -systems that don't support symbolic links. Also, don't use multiple -names for one file in different directories, because certain file -systems cannot handle this and that prevents unpacking the distribution. - - Try to make sure that all the file names will be unique on MS-DOS. A -name on MS-DOS consists of up to 8 characters, optionally followed by a -period and up to three characters. MS-DOS will truncate extra -characters both before and after the period. Thus, 'foobarhacker.c' and -'foobarhacker.o' are not ambiguous; they are truncated to 'foobarha.c' -and 'foobarha.o', which are distinct. - - Include in your distribution a copy of the 'texinfo.tex' you used to -test print any '*.texinfo' or '*.texi' files. - - Likewise, if your program uses small GNU software packages like -regex, getopt, obstack, or termcap, include them in the distribution -file. Leaving them out would make the distribution file a little -smaller at the expense of possible inconvenience to a user who doesn't -know what other files to get. - - -File: standards.info, Node: References, Next: GNU Free Documentation License, Prev: Managing Releases, Up: Top - -8 References to Non-Free Software and Documentation -*************************************************** - -A GNU program should not recommend, promote, or grant legitimacy to the -use of any non-free program. Proprietary software is a social and -ethical problem, and our aim is to put an end to that problem. We can't -stop some people from writing proprietary programs, or stop other people -from using them, but we can and should refuse to advertise them to new -potential customers, or to give the public the idea that their existence -is ethical. - - The GNU definition of free software is found on the GNU web site at -, and the definition of free -documentation is found at . -The terms "free" and "non-free", used in this document, refer to those -definitions. - - A list of important licenses and whether they qualify as free is in -. If it is not clear -whether a license qualifies as free, please ask the GNU Project by -writing to . We will answer, and if the license is -an important one, we will add it to the list. - - When a non-free program or system is well known, you can mention it -in passing--that is harmless, since users who might want to use it -probably already know about it. For instance, it is fine to explain how -to build your package on top of some widely used non-free operating -system, or how to use it together with some widely used non-free -program. - - However, you should give only the necessary information to help those -who already use the non-free program to use your program with it--don't -give, or refer to, any further information about the proprietary -program, and don't imply that the proprietary program enhances your -program, or that its existence is in any way a good thing. The goal -should be that people already using the proprietary program will get the -advice they need about how to use your free program with it, while -people who don't already use the proprietary program will not see -anything likely to lead them to take an interest in it. - - If a non-free program or system is obscure in your program's domain, -your program should not mention or support it at all, since doing so -would tend to popularize the non-free program more than it popularizes -your program. (You cannot hope to find many additional users for your -program among the users of Foobar, if the existence of Foobar is not -generally known among people who might want to use your program.) - - Sometimes a program is free software in itself but depends on a -non-free platform in order to run. For instance, many Java programs -depend on some non-free Java libraries. To recommend or promote such a -program is to promote the other programs it needs. This is why we are -careful about listing Java programs in the Free Software Directory: we -don't want to promote the non-free Java libraries. - - We hope this particular problem with Java will be gone by and by, as -we replace the remaining non-free standard Java libraries with free -software, but the general principle will remain the same: don't -recommend, promote or legitimize programs that depend on non-free -software to run. - - Some free programs strongly encourage the use of non-free software. -A typical example is 'mplayer'. It is free software in itself, and the -free code can handle some kinds of files. However, 'mplayer' recommends -use of non-free codecs for other kinds of files, and users that install -'mplayer' are very likely to install those codecs along with it. To -recommend 'mplayer' is, in effect, to promote use of the non-free -codecs. - - Thus, you should not recommend programs that strongly encourage the -use of non-free software. This is why we do not list 'mplayer' in the -Free Software Directory. - - A GNU package should not refer the user to any non-free documentation -for free software. Free documentation that can be included in free -operating systems is essential for completing the GNU system, or any -free operating system, so encouraging it is a priority; to recommend use -of documentation that we are not allowed to include undermines the -impetus for the community to produce documentation that we can include. -So GNU packages should never recommend non-free documentation. - - By contrast, it is ok to refer to journal articles and textbooks in -the comments of a program for explanation of how it functions, even -though they are non-free. This is because we don't include such things -in the GNU system even they are free--they are outside the scope of what -a software distribution needs to include. - - Referring to a web site that describes or recommends a non-free -program is promoting that program, so please do not make links (or -mention by name) web sites that contain such material. This policy is -relevant particularly for the web pages for a GNU package. - - Following links from nearly any web site can lead eventually to -non-free software; this is inherent in the nature of the web. So it -makes no sense to criticize a site for having such links. As long as -the site does not itself recommend a non-free program, there is no need -to consider the question of the sites that it links to for other -reasons. - - Thus, for example, you should not refer to AT&T's web site if that -recommends AT&T's non-free software packages; you should not refer to a -site that links to AT&T's site presenting it as a place to get some -non-free program, because that link recommends and legitimizes the -non-free program. However, that a site contains a link to AT&T's web -site for some other purpose (such as long-distance telephone service) is -not an objection against it. - - -File: standards.info, Node: GNU Free Documentation License, Next: Index, Prev: References, Up: Top - -Appendix A GNU Free Documentation License -***************************************** - - Version 1.3, 3 November 2008 - - Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. - - - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - 0. PREAMBLE - - The purpose of this License is to make a manual, textbook, or other - functional and useful document "free" in the sense of freedom: to - assure everyone the effective freedom to copy and redistribute it, - with or without modifying it, either commercially or - noncommercially. Secondarily, this License preserves for the - author and publisher a way to get credit for their work, while not - being considered responsible for modifications made by others. - - This License is a kind of "copyleft", which means that derivative - works of the document must themselves be free in the same sense. - It complements the GNU General Public License, which is a copyleft - license designed for free software. - - We have designed this License in order to use it for manuals for - free software, because free software needs free documentation: a - free program should come with manuals providing the same freedoms - that the software does. But this License is not limited to - software manuals; it can be used for any textual work, regardless - of subject matter or whether it is published as a printed book. We - recommend this License principally for works whose purpose is - instruction or reference. - - 1. APPLICABILITY AND DEFINITIONS - - This License applies to any manual or other work, in any medium, - that contains a notice placed by the copyright holder saying it can - be distributed under the terms of this License. Such a notice - grants a world-wide, royalty-free license, unlimited in duration, - to use that work under the conditions stated herein. The - "Document", below, refers to any such manual or work. Any member - of the public is a licensee, and is addressed as "you". You accept - the license if you copy, modify or distribute the work in a way - requiring permission under copyright law. - - A "Modified Version" of the Document means any work containing the - Document or a portion of it, either copied verbatim, or with - modifications and/or translated into another language. - - A "Secondary Section" is a named appendix or a front-matter section - of the Document that deals exclusively with the relationship of the - publishers or authors of the Document to the Document's overall - subject (or to related matters) and contains nothing that could - fall directly within that overall subject. (Thus, if the Document - is in part a textbook of mathematics, a Secondary Section may not - explain any mathematics.) The relationship could be a matter of - historical connection with the subject or with related matters, or - of legal, commercial, philosophical, ethical or political position - regarding them. - - The "Invariant Sections" are certain Secondary Sections whose - titles are designated, as being those of Invariant Sections, in the - notice that says that the Document is released under this License. - If a section does not fit the above definition of Secondary then it - is not allowed to be designated as Invariant. The Document may - contain zero Invariant Sections. If the Document does not identify - any Invariant Sections then there are none. - - The "Cover Texts" are certain short passages of text that are - listed, as Front-Cover Texts or Back-Cover Texts, in the notice - that says that the Document is released under this License. A - Front-Cover Text may be at most 5 words, and a Back-Cover Text may - be at most 25 words. - - A "Transparent" copy of the Document means a machine-readable copy, - represented in a format whose specification is available to the - general public, that is suitable for revising the document - straightforwardly with generic text editors or (for images composed - of pixels) generic paint programs or (for drawings) some widely - available drawing editor, and that is suitable for input to text - formatters or for automatic translation to a variety of formats - suitable for input to text formatters. A copy made in an otherwise - Transparent file format whose markup, or absence of markup, has - been arranged to thwart or discourage subsequent modification by - readers is not Transparent. An image format is not Transparent if - used for any substantial amount of text. A copy that is not - "Transparent" is called "Opaque". - - Examples of suitable formats for Transparent copies include plain - ASCII without markup, Texinfo input format, LaTeX input format, - SGML or XML using a publicly available DTD, and standard-conforming - simple HTML, PostScript or PDF designed for human modification. - Examples of transparent image formats include PNG, XCF and JPG. - Opaque formats include proprietary formats that can be read and - edited only by proprietary word processors, SGML or XML for which - the DTD and/or processing tools are not generally available, and - the machine-generated HTML, PostScript or PDF produced by some word - processors for output purposes only. - - The "Title Page" means, for a printed book, the title page itself, - plus such following pages as are needed to hold, legibly, the - material this License requires to appear in the title page. For - works in formats which do not have any title page as such, "Title - Page" means the text near the most prominent appearance of the - work's title, preceding the beginning of the body of the text. - - The "publisher" means any person or entity that distributes copies - of the Document to the public. - - A section "Entitled XYZ" means a named subunit of the Document - whose title either is precisely XYZ or contains XYZ in parentheses - following text that translates XYZ in another language. (Here XYZ - stands for a specific section name mentioned below, such as - "Acknowledgements", "Dedications", "Endorsements", or "History".) - To "Preserve the Title" of such a section when you modify the - Document means that it remains a section "Entitled XYZ" according - to this definition. - - The Document may include Warranty Disclaimers next to the notice - which states that this License applies to the Document. These - Warranty Disclaimers are considered to be included by reference in - this License, but only as regards disclaiming warranties: any other - implication that these Warranty Disclaimers may have is void and - has no effect on the meaning of this License. - - 2. VERBATIM COPYING - - You may copy and distribute the Document in any medium, either - commercially or noncommercially, provided that this License, the - copyright notices, and the license notice saying this License - applies to the Document are reproduced in all copies, and that you - add no other conditions whatsoever to those of this License. You - may not use technical measures to obstruct or control the reading - or further copying of the copies you make or distribute. However, - you may accept compensation in exchange for copies. If you - distribute a large enough number of copies you must also follow the - conditions in section 3. - - You may also lend copies, under the same conditions stated above, - and you may publicly display copies. - - 3. COPYING IN QUANTITY - - If you publish printed copies (or copies in media that commonly - have printed covers) of the Document, numbering more than 100, and - the Document's license notice requires Cover Texts, you must - enclose the copies in covers that carry, clearly and legibly, all - these Cover Texts: Front-Cover Texts on the front cover, and - Back-Cover Texts on the back cover. Both covers must also clearly - and legibly identify you as the publisher of these copies. The - front cover must present the full title with all words of the title - equally prominent and visible. You may add other material on the - covers in addition. Copying with changes limited to the covers, as - long as they preserve the title of the Document and satisfy these - conditions, can be treated as verbatim copying in other respects. - - If the required texts for either cover are too voluminous to fit - legibly, you should put the first ones listed (as many as fit - reasonably) on the actual cover, and continue the rest onto - adjacent pages. - - If you publish or distribute Opaque copies of the Document - numbering more than 100, you must either include a machine-readable - Transparent copy along with each Opaque copy, or state in or with - each Opaque copy a computer-network location from which the general - network-using public has access to download using public-standard - network protocols a complete Transparent copy of the Document, free - of added material. If you use the latter option, you must take - reasonably prudent steps, when you begin distribution of Opaque - copies in quantity, to ensure that this Transparent copy will - remain thus accessible at the stated location until at least one - year after the last time you distribute an Opaque copy (directly or - through your agents or retailers) of that edition to the public. - - It is requested, but not required, that you contact the authors of - the Document well before redistributing any large number of copies, - to give them a chance to provide you with an updated version of the - Document. - - 4. MODIFICATIONS - - You may copy and distribute a Modified Version of the Document - under the conditions of sections 2 and 3 above, provided that you - release the Modified Version under precisely this License, with the - Modified Version filling the role of the Document, thus licensing - distribution and modification of the Modified Version to whoever - possesses a copy of it. In addition, you must do these things in - the Modified Version: - - A. Use in the Title Page (and on the covers, if any) a title - distinct from that of the Document, and from those of previous - versions (which should, if there were any, be listed in the - History section of the Document). You may use the same title - as a previous version if the original publisher of that - version gives permission. - - B. List on the Title Page, as authors, one or more persons or - entities responsible for authorship of the modifications in - the Modified Version, together with at least five of the - principal authors of the Document (all of its principal - authors, if it has fewer than five), unless they release you - from this requirement. - - C. State on the Title page the name of the publisher of the - Modified Version, as the publisher. - - D. Preserve all the copyright notices of the Document. - - E. Add an appropriate copyright notice for your modifications - adjacent to the other copyright notices. - - F. Include, immediately after the copyright notices, a license - notice giving the public permission to use the Modified - Version under the terms of this License, in the form shown in - the Addendum below. - - G. Preserve in that license notice the full lists of Invariant - Sections and required Cover Texts given in the Document's - license notice. - - H. Include an unaltered copy of this License. - - I. Preserve the section Entitled "History", Preserve its Title, - and add to it an item stating at least the title, year, new - authors, and publisher of the Modified Version as given on the - Title Page. If there is no section Entitled "History" in the - Document, create one stating the title, year, authors, and - publisher of the Document as given on its Title Page, then add - an item describing the Modified Version as stated in the - previous sentence. - - J. Preserve the network location, if any, given in the Document - for public access to a Transparent copy of the Document, and - likewise the network locations given in the Document for - previous versions it was based on. These may be placed in the - "History" section. You may omit a network location for a work - that was published at least four years before the Document - itself, or if the original publisher of the version it refers - to gives permission. - - K. For any section Entitled "Acknowledgements" or "Dedications", - Preserve the Title of the section, and preserve in the section - all the substance and tone of each of the contributor - acknowledgements and/or dedications given therein. - - L. Preserve all the Invariant Sections of the Document, unaltered - in their text and in their titles. Section numbers or the - equivalent are not considered part of the section titles. - - M. Delete any section Entitled "Endorsements". Such a section - may not be included in the Modified Version. - - N. Do not retitle any existing section to be Entitled - "Endorsements" or to conflict in title with any Invariant - Section. - - O. Preserve any Warranty Disclaimers. - - If the Modified Version includes new front-matter sections or - appendices that qualify as Secondary Sections and contain no - material copied from the Document, you may at your option designate - some or all of these sections as invariant. To do this, add their - titles to the list of Invariant Sections in the Modified Version's - license notice. These titles must be distinct from any other - section titles. - - You may add a section Entitled "Endorsements", provided it contains - nothing but endorsements of your Modified Version by various - parties--for example, statements of peer review or that the text - has been approved by an organization as the authoritative - definition of a standard. - - You may add a passage of up to five words as a Front-Cover Text, - and a passage of up to 25 words as a Back-Cover Text, to the end of - the list of Cover Texts in the Modified Version. Only one passage - of Front-Cover Text and one of Back-Cover Text may be added by (or - through arrangements made by) any one entity. If the Document - already includes a cover text for the same cover, previously added - by you or by arrangement made by the same entity you are acting on - behalf of, you may not add another; but you may replace the old - one, on explicit permission from the previous publisher that added - the old one. - - The author(s) and publisher(s) of the Document do not by this - License give permission to use their names for publicity for or to - assert or imply endorsement of any Modified Version. - - 5. COMBINING DOCUMENTS - - You may combine the Document with other documents released under - this License, under the terms defined in section 4 above for - modified versions, provided that you include in the combination all - of the Invariant Sections of all of the original documents, - unmodified, and list them all as Invariant Sections of your - combined work in its license notice, and that you preserve all - their Warranty Disclaimers. - - The combined work need only contain one copy of this License, and - multiple identical Invariant Sections may be replaced with a single - copy. If there are multiple Invariant Sections with the same name - but different contents, make the title of each such section unique - by adding at the end of it, in parentheses, the name of the - original author or publisher of that section if known, or else a - unique number. Make the same adjustment to the section titles in - the list of Invariant Sections in the license notice of the - combined work. - - In the combination, you must combine any sections Entitled - "History" in the various original documents, forming one section - Entitled "History"; likewise combine any sections Entitled - "Acknowledgements", and any sections Entitled "Dedications". You - must delete all sections Entitled "Endorsements." - - 6. COLLECTIONS OF DOCUMENTS - - You may make a collection consisting of the Document and other - documents released under this License, and replace the individual - copies of this License in the various documents with a single copy - that is included in the collection, provided that you follow the - rules of this License for verbatim copying of each of the documents - in all other respects. - - You may extract a single document from such a collection, and - distribute it individually under this License, provided you insert - a copy of this License into the extracted document, and follow this - License in all other respects regarding verbatim copying of that - document. - - 7. AGGREGATION WITH INDEPENDENT WORKS - - A compilation of the Document or its derivatives with other - separate and independent documents or works, in or on a volume of a - storage or distribution medium, is called an "aggregate" if the - copyright resulting from the compilation is not used to limit the - legal rights of the compilation's users beyond what the individual - works permit. When the Document is included in an aggregate, this - License does not apply to the other works in the aggregate which - are not themselves derivative works of the Document. - - If the Cover Text requirement of section 3 is applicable to these - copies of the Document, then if the Document is less than one half - of the entire aggregate, the Document's Cover Texts may be placed - on covers that bracket the Document within the aggregate, or the - electronic equivalent of covers if the Document is in electronic - form. Otherwise they must appear on printed covers that bracket - the whole aggregate. - - 8. TRANSLATION - - Translation is considered a kind of modification, so you may - distribute translations of the Document under the terms of section - 4. Replacing Invariant Sections with translations requires special - permission from their copyright holders, but you may include - translations of some or all Invariant Sections in addition to the - original versions of these Invariant Sections. You may include a - translation of this License, and all the license notices in the - Document, and any Warranty Disclaimers, provided that you also - include the original English version of this License and the - original versions of those notices and disclaimers. In case of a - disagreement between the translation and the original version of - this License or a notice or disclaimer, the original version will - prevail. - - If a section in the Document is Entitled "Acknowledgements", - "Dedications", or "History", the requirement (section 4) to - Preserve its Title (section 1) will typically require changing the - actual title. - - 9. TERMINATION - - You may not copy, modify, sublicense, or distribute the Document - except as expressly provided under this License. Any attempt - otherwise to copy, modify, sublicense, or distribute it is void, - and will automatically terminate your rights under this License. - - However, if you cease all violation of this License, then your - license from a particular copyright holder is reinstated (a) - provisionally, unless and until the copyright holder explicitly and - finally terminates your license, and (b) permanently, if the - copyright holder fails to notify you of the violation by some - reasonable means prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is - reinstated permanently if the copyright holder notifies you of the - violation by some reasonable means, this is the first time you have - received notice of violation of this License (for any work) from - that copyright holder, and you cure the violation prior to 30 days - after your receipt of the notice. - - Termination of your rights under this section does not terminate - the licenses of parties who have received copies or rights from you - under this License. If your rights have been terminated and not - permanently reinstated, receipt of a copy of some or all of the - same material does not give you any rights to use it. - - 10. FUTURE REVISIONS OF THIS LICENSE - - The Free Software Foundation may publish new, revised versions of - the GNU Free Documentation License from time to time. Such new - versions will be similar in spirit to the present version, but may - differ in detail to address new problems or concerns. See - . - - Each version of the License is given a distinguishing version - number. If the Document specifies that a particular numbered - version of this License "or any later version" applies to it, you - have the option of following the terms and conditions either of - that specified version or of any later version that has been - published (not as a draft) by the Free Software Foundation. If the - Document does not specify a version number of this License, you may - choose any version ever published (not as a draft) by the Free - Software Foundation. If the Document specifies that a proxy can - decide which future versions of this License can be used, that - proxy's public statement of acceptance of a version permanently - authorizes you to choose that version for the Document. - - 11. RELICENSING - - "Massive Multiauthor Collaboration Site" (or "MMC Site") means any - World Wide Web server that publishes copyrightable works and also - provides prominent facilities for anybody to edit those works. A - public wiki that anybody can edit is an example of such a server. - A "Massive Multiauthor Collaboration" (or "MMC") contained in the - site means any set of copyrightable works thus published on the MMC - site. - - "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 - license published by Creative Commons Corporation, a not-for-profit - corporation with a principal place of business in San Francisco, - California, as well as future copyleft versions of that license - published by that same organization. - - "Incorporate" means to publish or republish a Document, in whole or - in part, as part of another Document. - - An MMC is "eligible for relicensing" if it is licensed under this - License, and if all works that were first published under this - License somewhere other than this MMC, and subsequently - incorporated in whole or in part into the MMC, (1) had no cover - texts or invariant sections, and (2) were thus incorporated prior - to November 1, 2008. - - The operator of an MMC Site may republish an MMC contained in the - site under CC-BY-SA on the same site at any time before August 1, - 2009, provided the MMC is eligible for relicensing. - -ADDENDUM: How to use this License for your documents -==================================================== - -To use this License in a document you have written, include a copy of -the License in the document and put the following copyright and license -notices just after the title page: - - Copyright (C) YEAR YOUR NAME. - Permission is granted to copy, distribute and/or modify this document - under the terms of the GNU Free Documentation License, Version 1.3 - or any later version published by the Free Software Foundation; - with no Invariant Sections, no Front-Cover Texts, and no Back-Cover - Texts. A copy of the license is included in the section entitled ``GNU - Free Documentation License''. - - If you have Invariant Sections, Front-Cover Texts and Back-Cover -Texts, replace the "with...Texts." line with this: - - with the Invariant Sections being LIST THEIR TITLES, with - the Front-Cover Texts being LIST, and with the Back-Cover Texts - being LIST. - - If you have Invariant Sections without Cover Texts, or some other -combination of the three, merge those two alternatives to suit the -situation. - - If your document contains nontrivial examples of program code, we -recommend releasing these examples in parallel under your choice of free -software license, such as the GNU General Public License, to permit -their use in free software. - - -File: standards.info, Node: Index, Prev: GNU Free Documentation License, Up: Top - -Index -***** - -[index] -* Menu: - -* '#endif', commenting: Comments. (line 60) -* '--help' output: --help. (line 6) -* '--version' output: --version. (line 6) -* '-Wall' compiler option: Syntactic Conventions. - (line 10) -* accepting contributions: Contributions. (line 6) -* address for bug reports: --help. (line 11) -* ANSI C standard: Standard C. (line 6) -* arbitrary limits on data: Semantics. (line 6) -* ASCII characters: Character Set. (line 6) -* autoconf: System Portability. (line 23) -* avoiding proprietary code: Reading Non-Free Code. - (line 6) -* behavior, dependent on program's name: User Interfaces. (line 6) -* binary packages: Install Command Categories. - (line 80) -* bindir: Directory Variables. (line 54) -* braces, in C source: Formatting. (line 6) -* bug reports: --help. (line 11) -* 'bug-standards@gnu.org' email address: Preface. (line 30) -* canonical name of a program: --version. (line 12) -* casting pointers to integers: CPU Portability. (line 88) -* CGI programs, standard options for: Command-Line Interfaces. - (line 31) -* change logs: Change Logs. (line 6) -* change logs, conditional changes: Conditional Changes. (line 6) -* change logs, style: Style of Change Logs. - (line 6) -* character set: Character Set. (line 6) -* command-line arguments, decoding: Semantics. (line 46) -* command-line interface: Command-Line Interfaces. - (line 6) -* commenting: Comments. (line 6) -* compatibility with C and POSIX standards: Compatibility. (line 6) -* compiler warnings: Syntactic Conventions. - (line 10) -* conditional changes, and change logs: Conditional Changes. (line 6) -* conditionals, comments for: Comments. (line 60) -* configure: Configuration. (line 6) -* control-L: Formatting. (line 118) -* conventions for makefiles: Makefile Conventions. - (line 6) -* CORBA: Graphical Interfaces. - (line 16) -* credits for manuals: Manual Credits. (line 6) -* D-bus: Graphical Interfaces. - (line 16) -* data types, and portability: CPU Portability. (line 6) -* declaration for system functions: System Functions. (line 21) -* DESTDIR: DESTDIR. (line 6) -* documentation: Documentation. (line 6) -* doschk: Names. (line 38) -* downloading this manual: Preface. (line 14) -* encodings: Character Set. (line 6) -* error messages: Semantics. (line 19) -* error messages, formatting: Errors. (line 6) -* exec_prefix: Directory Variables. (line 36) -* expressions, splitting: Formatting. (line 81) -* FDL, GNU Free Documentation License: GNU Free Documentation License. - (line 6) -* file usage: File Usage. (line 6) -* file-name limitations: Names. (line 38) -* formatting error messages: Errors. (line 6) -* formatting source code: Formatting. (line 6) -* formfeed: Formatting. (line 118) -* function argument, declaring: Syntactic Conventions. - (line 6) -* function prototypes: Standard C. (line 17) -* getopt: Command-Line Interfaces. - (line 6) -* gettext: Internationalization. - (line 6) -* GNOME: Graphical Interfaces. - (line 16) -* GNOME and Guile: Source Language. (line 37) -* gnustandards project repository: Preface. (line 30) -* 'gnustandards-commit@gnu.org' mailing list: Preface. (line 24) -* graphical user interface: Graphical Interfaces. - (line 6) -* grave accent: Quote Characters. (line 6) -* GTK+: Graphical Interfaces. - (line 6) -* Guile: Source Language. (line 37) -* implicit 'int': Syntactic Conventions. - (line 6) -* impossible conditions: Semantics. (line 70) -* installations, staged: DESTDIR. (line 6) -* interface styles: Graphical Interfaces. - (line 6) -* internationalization: Internationalization. - (line 6) -* keyboard interface: Graphical Interfaces. - (line 16) -* LDAP: OID Allocations. (line 6) -* left quote: Quote Characters. (line 6) -* legal aspects: Legal Issues. (line 6) -* legal papers: Contributions. (line 6) -* libexecdir: Directory Variables. (line 67) -* libraries: Libraries. (line 6) -* library functions, and portability: System Functions. (line 6) -* library interface: Graphical Interfaces. - (line 16) -* license for manuals: License for Manuals. (line 6) -* lint: Syntactic Conventions. - (line 109) -* locale-specific quote characters: Quote Characters. (line 6) -* long option names: Option Table. (line 6) -* long-named options: Command-Line Interfaces. - (line 12) -* makefile, conventions for: Makefile Conventions. - (line 6) -* 'malloc' return value: Semantics. (line 25) -* man pages: Man Pages. (line 6) -* manual structure: Manual Structure Details. - (line 6) -* memory allocation failure: Semantics. (line 25) -* memory usage: Memory Usage. (line 6) -* message text, and internationalization: Internationalization. - (line 29) -* mmap: Mmap. (line 6) -* multiple variables in a line: Syntactic Conventions. - (line 35) -* names of variables, functions, and files: Names. (line 6) -* 'NEWS' file: NEWS File. (line 6) -* non-ASCII characters: Character Set. (line 6) -* non-POSIX systems, and portability: System Portability. (line 32) -* non-standard extensions: Using Extensions. (line 6) -* 'NUL' characters: Semantics. (line 11) -* OID allocations for GNU: OID Allocations. (line 6) -* open brace: Formatting. (line 6) -* optional features, configure-time: Configuration. (line 97) -* options for compatibility: Compatibility. (line 14) -* options, standard command-line: Command-Line Interfaces. - (line 31) -* output device and program's behavior: User Interfaces. (line 13) -* packaging: Releases. (line 6) -* PATH_INFO, specifying standard options as: Command-Line Interfaces. - (line 31) -* portability, and data types: CPU Portability. (line 6) -* portability, and library functions: System Functions. (line 6) -* portability, between system types: System Portability. (line 6) -* POSIX compatibility: Compatibility. (line 6) -* 'POSIXLY_CORRECT', environment variable: Compatibility. (line 21) -* post-installation commands: Install Command Categories. - (line 6) -* pre-installation commands: Install Command Categories. - (line 6) -* prefix: Directory Variables. (line 26) -* program configuration: Configuration. (line 6) -* program design: Design Advice. (line 6) -* program name and its behavior: User Interfaces. (line 6) -* program's canonical name: --version. (line 12) -* programming languages: Source Language. (line 6) -* proprietary programs: Reading Non-Free Code. - (line 6) -* quote characters: Quote Characters. (line 6) -* 'README' file: Releases. (line 21) -* references to non-free material: References. (line 6) -* releasing: Managing Releases. (line 6) -* Savannah repository for gnustandards: Preface. (line 30) -* sbindir: Directory Variables. (line 60) -* signal handling: Semantics. (line 59) -* SNMP: OID Allocations. (line 6) -* spaces before open-paren: Formatting. (line 75) -* staged installs: DESTDIR. (line 6) -* standard command-line options: Command-Line Interfaces. - (line 31) -* standards for makefiles: Makefile Conventions. - (line 6) -* string library functions: System Functions. (line 54) -* syntactic conventions: Syntactic Conventions. - (line 6) -* table of long options: Option Table. (line 6) -* temporary files: Semantics. (line 84) -* temporary variables: Syntactic Conventions. - (line 23) -* 'texinfo.tex', in a distribution: Releases. (line 70) -* 'TMPDIR' environment variable: Semantics. (line 84) -* trademarks: Trademarks. (line 6) -* user interface styles: Graphical Interfaces. - (line 6) -* where to obtain 'standards.texi': Preface. (line 14) -* X.509: OID Allocations. (line 6) - - - -Tag Table: -Node: Top808 -Node: Preface2083 -Node: Legal Issues4784 -Node: Reading Non-Free Code5254 -Node: Contributions6983 -Node: Trademarks9221 -Node: Design Advice10855 -Node: Source Language11447 -Node: Compatibility13566 -Node: Using Extensions15194 -Node: Standard C16771 -Node: Conditional Compilation19174 -Node: Program Behavior20572 -Node: Non-GNU Standards21688 -Node: Semantics23969 -Node: Libraries28689 -Node: Errors29934 -Node: User Interfaces32428 -Node: Graphical Interfaces34033 -Node: Command-Line Interfaces35216 -Node: --version37246 -Node: --help42965 -Node: Option Table43838 -Node: OID Allocations58793 -Node: Memory Usage60590 -Node: File Usage61626 -Node: Writing C62376 -Node: Formatting63346 -Node: Comments67635 -Node: Syntactic Conventions71186 -Node: Names74648 -Node: System Portability76860 -Node: CPU Portability79751 -Node: System Functions83653 -Node: Internationalization88845 -Node: Character Set92839 -Node: Quote Characters93652 -Node: Mmap95172 -Node: Documentation95880 -Node: GNU Manuals96986 -Node: Doc Strings and Manuals102724 -Node: Manual Structure Details104277 -Node: License for Manuals105695 -Node: Manual Credits106668 -Node: Printed Manuals107061 -Node: NEWS File107747 -Node: Change Logs108425 -Node: Change Log Concepts109179 -Node: Style of Change Logs111282 -Node: Simple Changes113782 -Node: Conditional Changes115224 -Node: Indicating the Part Changed116646 -Node: Man Pages117173 -Node: Reading other Manuals119347 -Node: Managing Releases120138 -Node: Configuration120918 -Node: Makefile Conventions129581 -Node: Makefile Basics130463 -Node: Utilities in Makefiles133637 -Node: Command Variables135783 -Node: DESTDIR139006 -Node: Directory Variables141155 -Node: Standard Targets155640 -Ref: Standard Targets-Footnote-1169156 -Node: Install Command Categories169257 -Node: Releases173790 -Node: References177794 -Node: GNU Free Documentation License183640 -Node: Index208788 - -End Tag Table diff --git a/libc/xtensa-lx106-elf/include/_newlib_version.h b/libc/xtensa-lx106-elf/include/_newlib_version.h new file mode 100644 index 0000000..73b527e --- /dev/null +++ b/libc/xtensa-lx106-elf/include/_newlib_version.h @@ -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__ */ + diff --git a/libc/xtensa-lx106-elf/include/complex.h b/libc/xtensa-lx106-elf/include/complex.h index 969b20e..0a3ea97 100644 --- a/libc/xtensa-lx106-elf/include/complex.h +++ b/libc/xtensa-lx106-elf/include/complex.h @@ -24,10 +24,12 @@ float complex cacosf(float complex); /* 7.3.5.2 The casin functions */ double complex casin(double complex); float complex casinf(float complex); +long double complex casinl(long double complex); /* 7.3.5.1 The catan functions */ double complex catan(double complex); float complex catanf(float complex); +long double complex catanl(long double complex); /* 7.3.5.1 The ccos functions */ double complex ccos(double complex); @@ -74,6 +76,7 @@ float complex cexpf(float complex); /* 7.3.7.2 The clog functions */ double complex clog(double complex); float complex clogf(float complex); +long double complex clogl(long double complex); /* 7.3.8 Power and absolute-value functions */ /* 7.3.8.1 The cabs functions */ @@ -83,6 +86,7 @@ float complex clogf(float complex); float cabsf(float complex) __RENAME(__c99_cabsf); #endif */ +long double cabsl(long double complex) ; double cabs(double complex) ; float cabsf(float complex) ; @@ -93,31 +97,56 @@ float complex cpowf(float complex, float complex); /* 7.3.8.3 The csqrt functions */ double complex csqrt(double complex); float complex csqrtf(float complex); +long double complex csqrtl(long double complex); /* 7.3.9 Manipulation functions */ /* 7.3.9.1 The carg functions */ double carg(double complex); float cargf(float complex); +long double cargl(long double complex); /* 7.3.9.2 The cimag functions */ double cimag(double complex); float cimagf(float complex); -/*long double cimagl(long double complex); */ +long double cimagl(long double complex); /* 7.3.9.3 The conj functions */ double complex conj(double complex); float complex conjf(float complex); -/*long double complex conjl(long double complex); */ /* 7.3.9.4 The cproj functions */ double complex cproj(double complex); float complex cprojf(float complex); -/*long double complex cprojl(long double complex); */ /* 7.3.9.5 The creal functions */ double creal(double 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 diff --git a/libc/xtensa-lx106-elf/include/cpio.h b/libc/xtensa-lx106-elf/include/cpio.h new file mode 100644 index 0000000..99860b2 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/cpio.h @@ -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 */ diff --git a/libc/xtensa-lx106-elf/include/ctype.h b/libc/xtensa-lx106-elf/include/ctype.h index 56ad5ab..06458cb 100644 --- a/libc/xtensa-lx106-elf/include/ctype.h +++ b/libc/xtensa-lx106-elf/include/ctype.h @@ -2,6 +2,11 @@ #define _CTYPE_H_ #include "_ansi.h" +#include + +#if __POSIX_VISIBLE >= 200809 || __MISC_VISIBLE || defined (_COMPILING_NEWLIB) +#include +#endif _BEGIN_STD_C @@ -19,17 +24,39 @@ int _EXFUN(isxdigit,(int __c)); int _EXFUN(tolower, (int __c)); int _EXFUN(toupper, (int __c)); -#if !defined(__STRICT_ANSI__) || defined(__cplusplus) || __STDC_VERSION__ >= 199901L +#if __ISO_C_VISIBLE >= 1999 int _EXFUN(isblank, (int __c)); #endif -#ifndef __STRICT_ANSI__ +#if __MISC_VISIBLE || __XSI_VISIBLE int _EXFUN(isascii, (int __c)); int _EXFUN(toascii, (int __c)); #define _tolower(__c) ((unsigned char)(__c) - 'A' + 'a') #define _toupper(__c) ((unsigned char)(__c) - 'a' + 'A') #endif +#if __POSIX_VISIBLE >= 200809 +extern int isalnum_l (int __c, locale_t __l); +extern int isalpha_l (int __c, locale_t __l); +extern int isblank_l (int __c, locale_t __l); +extern int iscntrl_l (int __c, locale_t __l); +extern int isdigit_l (int __c, locale_t __l); +extern int isgraph_l (int __c, locale_t __l); +extern int islower_l (int __c, locale_t __l); +extern int isprint_l (int __c, locale_t __l); +extern int ispunct_l (int __c, locale_t __l); +extern int isspace_l (int __c, locale_t __l); +extern int isupper_l (int __c, locale_t __l); +extern int isxdigit_l(int __c, locale_t __l); +extern int tolower_l (int __c, locale_t __l); +extern int toupper_l (int __c, locale_t __l); +#endif + +#if __MISC_VISIBLE +extern int isascii_l (int __c, locale_t __l); +extern int toascii_l (int __c, locale_t __l); +#endif + #define _U 01 #define _L 02 #define _N 04 @@ -39,22 +66,20 @@ int _EXFUN(toascii, (int __c)); #define _X 0100 #define _B 0200 -#ifndef _MB_CAPABLE -_CONST -#endif -extern __IMPORT char *__ctype_ptr__; +const char *__locale_ctype_ptr (void); +# define __CTYPE_PTR (__locale_ctype_ptr ()) #ifndef __cplusplus /* These macros are intentionally written in a manner that will trigger a gcc -Wall warning if the user mistakenly passes a 'char' instead of an int containing an 'unsigned char'. Note that the sizeof will - always be 1, which is what we want for mapping EOF to __ctype_ptr__[0]; + always be 1, which is what we want for mapping EOF to __CTYPE_PTR[0]; the use of a raw index inside the sizeof triggers the gcc warning if __c was of type char, and sizeof masks side effects of the extra __c. - Meanwhile, the real index to __ctype_ptr__+1 must be cast to int, + Meanwhile, the real index to __CTYPE_PTR+1 must be cast to int, since isalpha(0x100000001LL) must equal isalpha(1), rather than being an out-of-bounds reference on a 64-bit machine. */ -#define __ctype_lookup(__c) ((__ctype_ptr__+sizeof(""[__c]))[(int)(__c)]) +#define __ctype_lookup(__c) ((__CTYPE_PTR+sizeof(""[__c]))[(int)(__c)]) #define isalpha(__c) (__ctype_lookup(__c)&(_U|_L)) #define isupper(__c) ((__ctype_lookup(__c)&(_U|_L))==_U) @@ -68,13 +93,45 @@ extern __IMPORT char *__ctype_ptr__; #define isgraph(__c) (__ctype_lookup(__c)&(_P|_U|_L|_N)) #define iscntrl(__c) (__ctype_lookup(__c)&_C) -#if defined(__GNUC__) && \ - (!defined(__STRICT_ANSI__) || __STDC_VERSION__ >= 199901L) +#if defined(__GNUC__) && __ISO_C_VISIBLE >= 1999 #define isblank(__c) \ __extension__ ({ __typeof__ (__c) __x = (__c); \ (__ctype_lookup(__x)&_B) || (int) (__x) == '\t';}) #endif +#if __POSIX_VISIBLE >= 200809 +const char *__locale_ctype_ptr_l (locale_t); +#define __ctype_lookup_l(__c,__l) ((__locale_ctype_ptr_l(__l)+sizeof(""[__c]))[(int)(__c)]) + +#define isalpha_l(__c,__l) (__ctype_lookup_l(__c,__l)&(_U|_L)) +#define isupper_l(__c,__l) ((__ctype_lookup_l(__c,__l)&(_U|_L))==_U) +#define islower_l(__c,__l) ((__ctype_lookup_l(__c,__l)&(_U|_L))==_L) +#define isdigit_l(__c,__l) (__ctype_lookup_l(__c,__l)&_N) +#define isxdigit_l(__c,__l) (__ctype_lookup_l(__c,__l)&(_X|_N)) +#define isspace_l(__c,__l) (__ctype_lookup_l(__c,__l)&_S) +#define ispunct_l(__c,__l) (__ctype_lookup_l(__c,__l)&_P) +#define isalnum_l(__c,__l) (__ctype_lookup_l(__c,__l)&(_U|_L|_N)) +#define isprint_l(__c,__l) (__ctype_lookup_l(__c,__l)&(_P|_U|_L|_N|_B)) +#define isgraph_l(__c,__l) (__ctype_lookup_l(__c,__l)&(_P|_U|_L|_N)) +#define iscntrl_l(__c,__l) (__ctype_lookup_l(__c,__l)&_C) + +#if defined(__GNUC__) +#define isblank_l(__c, __l) \ + __extension__ ({ __typeof__ (__c) __x = (__c); \ + (__ctype_lookup_l(__x,__l)&_B) || (int) (__x) == '\t';}) +#endif + +#endif /* __POSIX_VISIBLE >= 200809 */ + +#if __MISC_VISIBLE || __XSI_VISIBLE +#define isascii(__c) ((unsigned)(__c)<=0177) +#define toascii(__c) ((__c)&0177) +#endif + +#if __MISC_VISIBLE +#define isascii_l(__c,__l) ((__l),(unsigned)(__c)<=0177) +#define toascii_l(__c,__l) ((__l),(__c)&0177) +#endif /* Non-gcc versions will get the library versions, and will be slightly slower. These macros are not NLS-aware so they are @@ -92,18 +149,17 @@ extern __IMPORT char *__ctype_ptr__; function. */ # define toupper(__c) \ __extension__ ({ __typeof__ (__c) __x = (__c); \ - (void) __ctype_ptr__[__x]; (toupper) (__x);}) + (void) __CTYPE_PTR[__x]; (toupper) (__x);}) # define tolower(__c) \ __extension__ ({ __typeof__ (__c) __x = (__c); \ - (void) __ctype_ptr__[__x]; (tolower) (__x);}) + (void) __CTYPE_PTR[__x]; (tolower) (__x);}) # endif /* _MB_EXTENDED_CHARSETS* */ # endif /* __GNUC__ */ -#endif /* !__cplusplus */ -#ifndef __STRICT_ANSI__ -#define isascii(__c) ((unsigned)(__c)<=0177) -#define toascii(__c) ((__c)&0177) -#endif +#if __POSIX_VISIBLE >= 200809 +#endif /* __POSIX_VISIBLE >= 200809 */ + +#endif /* !__cplusplus */ /* For C++ backward-compatibility only. */ extern __IMPORT _CONST char _ctype_[]; diff --git a/libc/xtensa-lx106-elf/include/devctl.h b/libc/xtensa-lx106-elf/include/devctl.h new file mode 100644 index 0000000..f6055fb --- /dev/null +++ b/libc/xtensa-lx106-elf/include/devctl.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016 Joel Sherrill . 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _POSIX_DEVCTL_h_ +#define _POSIX_DEVCTL_h_ + +/* + * The posix_devctl() method is defined by POSIX 1003.26-2003. Aside + * from the single method, it adds the following requirements: + * + * + define _POSIX_26_VERSION to 200312L + * + add _SC_POSIX_26_VERSION in . Return _POSIX_26_VERSION + * + application must define _POSIX_26_C_SOURCE to use posix_devctl(). + * + posix_devctl() is prototyped in + */ + +#ifdef _POSIX_26_C_SOURCE +#include + +int posix_devctl( + int fd, + int dcmd, + void *__restrict dev_data_ptr, + size_t nbyte, + int *__restrict dev_info_ptr +); +#endif + +#endif diff --git a/libc/xtensa-lx106-elf/include/dirent.h b/libc/xtensa-lx106-elf/include/dirent.h index 6fefc03..6135b9f 100644 --- a/libc/xtensa-lx106-elf/include/dirent.h +++ b/libc/xtensa-lx106-elf/include/dirent.h @@ -3,9 +3,10 @@ #ifdef __cplusplus extern "C" { #endif +#include #include -#if !defined(MAXNAMLEN) && !defined(_POSIX_SOURCE) +#if !defined(MAXNAMLEN) && __BSD_VISIBLE #define MAXNAMLEN 1024 #endif diff --git a/libc/xtensa-lx106-elf/include/fnmatch.h b/libc/xtensa-lx106-elf/include/fnmatch.h index 06311fc..a94e923 100644 --- a/libc/xtensa-lx106-elf/include/fnmatch.h +++ b/libc/xtensa-lx106-elf/include/fnmatch.h @@ -33,21 +33,21 @@ #ifndef _FNMATCH_H_ #define _FNMATCH_H_ +#include + #define FNM_NOMATCH 1 /* Match failed. */ #define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ #define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ #define FNM_PERIOD 0x04 /* Period must be matched by period. */ -#if defined(_GNU_SOURCE) || !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +#if __GNU_VISIBLE #define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ #define FNM_CASEFOLD 0x10 /* Case insensitive search. */ #define FNM_IGNORECASE FNM_CASEFOLD #define FNM_FILE_NAME FNM_PATHNAME #endif -#include - __BEGIN_DECLS int fnmatch(const char *, const char *, int); __END_DECLS diff --git a/libc/xtensa-lx106-elf/include/grp.h b/libc/xtensa-lx106-elf/include/grp.h index c3a5a67..6a26564 100644 --- a/libc/xtensa-lx106-elf/include/grp.h +++ b/libc/xtensa-lx106-elf/include/grp.h @@ -49,7 +49,7 @@ #include #endif -#if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE) +#if __BSD_VISIBLE #define _PATH_GROUP "/etc/group" #endif @@ -67,25 +67,20 @@ extern "C" { #ifndef __INSIDE_CYGWIN__ struct group *getgrgid (gid_t); struct group *getgrnam (const char *); +#if __MISC_VISIBLE || __POSIX_VISIBLE int getgrnam_r (const char *, struct group *, char *, size_t, struct group **); int getgrgid_r (gid_t, struct group *, char *, size_t, struct group **); -#ifndef _POSIX_SOURCE +#endif /* __MISC_VISIBLE || __POSIX_VISIBLE */ +#if __MISC_VISIBLE || __XSI_VISIBLE >= 4 struct group *getgrent (void); void setgrent (void); void endgrent (void); -#ifndef __CYGWIN__ -void setgrfile (const char *); -#endif /* !__CYGWIN__ */ -#ifndef _XOPEN_SOURCE -#ifndef __CYGWIN__ -char *group_from_gid (gid_t, int); -int setgroupent (int); -#endif /* !__CYGWIN__ */ +#endif /* __MISC_VISIBLE || __XSI_VISIBLE >= 4 */ +#if __BSD_VISIBLE int initgroups (const char *, gid_t); -#endif /* !_XOPEN_SOURCE */ -#endif /* !_POSIX_SOURCE */ +#endif /* __BSD_VISIBLE */ #endif /* !__INSIDE_CYGWIN__ */ #ifdef __cplusplus diff --git a/libc/xtensa-lx106-elf/include/ieeefp.h b/libc/xtensa-lx106-elf/include/ieeefp.h index 0b06fb7..2c04284 100644 --- a/libc/xtensa-lx106-elf/include/ieeefp.h +++ b/libc/xtensa-lx106-elf/include/ieeefp.h @@ -4,11 +4,12 @@ #include "_ansi.h" #include +#include _BEGIN_STD_C /* FIXME FIXME FIXME: - Neither of __ieee_{float,double}_shape_tape seem to be used anywhere + Neither of __ieee_{float,double}_shape_type seem to be used anywhere except in libm/test. If that is the case, please delete these from here. If that is not the case, please insert documentation here describing why they're needed. */ @@ -46,9 +47,7 @@ typedef union long aslong[2]; } __ieee_double_shape_type; -#endif - -#ifdef __IEEE_LITTLE_ENDIAN +#elif defined __IEEE_LITTLE_ENDIAN typedef union { @@ -92,7 +91,7 @@ typedef union } __ieee_double_shape_type; -#endif +#endif /* __IEEE_LITTLE_ENDIAN */ #ifdef __IEEE_BIG_ENDIAN @@ -118,9 +117,7 @@ typedef union } __ieee_float_shape_type; -#endif - -#ifdef __IEEE_LITTLE_ENDIAN +#elif defined __IEEE_LITTLE_ENDIAN typedef union { @@ -144,10 +141,70 @@ typedef union } __ieee_float_shape_type; +#endif /* __IEEE_LITTLE_ENDIAN */ + +#ifndef _LDBL_EQ_DBL + +#ifndef LDBL_MANT_DIG +#error "LDBL_MANT_DIG not defined - should be found in float.h" + +#elif LDBL_MANT_DIG == DBL_MANT_DIG +#error "double and long double are the same size but LDBL_EQ_DBL is not defined" + +#elif LDBL_MANT_DIG == 53 +/* This happens when doubles are 32-bits and long doubles are 64-bits. */ +#define EXT_EXPBITS 11 +#define EXT_FRACHBITS 20 +#define EXT_FRACLBITS 32 +#define __ieee_ext_field_type unsigned long + +#elif LDBL_MANT_DIG == 64 +#define EXT_EXPBITS 15 +#define EXT_FRACHBITS 32 +#define EXT_FRACLBITS 32 +#define __ieee_ext_field_type unsigned int + +#elif LDBL_MANT_DIG == 65 +#define EXT_EXPBITS 15 +#define EXT_FRACHBITS 32 +#define EXT_FRACLBITS 32 +#define __ieee_ext_field_type unsigned int + +#elif LDBL_MANT_DIG == 112 +#define EXT_EXPBITS 15 +#define EXT_FRACHBITS 48 +#define EXT_FRACLBITS 64 +#define __ieee_ext_field_type unsigned long long + +#elif LDBL_MANT_DIG == 113 +#define EXT_EXPBITS 15 +#define EXT_FRACHBITS 48 +#define EXT_FRACLBITS 64 +#define __ieee_ext_field_type unsigned long long + +#else +#error Unsupported value for LDBL_MANT_DIG #endif +#define EXT_EXP_INFNAN ((1 << EXT_EXPBITS) - 1) /* 32767 */ +#define EXT_EXP_BIAS ((1 << (EXT_EXPBITS - 1)) - 1) /* 16383 */ +#define EXT_FRACBITS (EXT_FRACLBITS + EXT_FRACHBITS) +typedef struct ieee_ext +{ + __ieee_ext_field_type ext_fracl : EXT_FRACLBITS; + __ieee_ext_field_type ext_frach : EXT_FRACHBITS; + __ieee_ext_field_type ext_exp : EXT_EXPBITS; + __ieee_ext_field_type ext_sign : 1; +} ieee_ext; +typedef union ieee_ext_u +{ + long double extu_ld; + struct ieee_ext extu_ext; +} ieee_ext_u; + +#endif /* ! _LDBL_EQ_DBL */ /* FLOATING ROUNDING */ @@ -184,19 +241,6 @@ typedef int fp_rdi; fp_rdi _EXFUN(fpgetroundtoi,(void)); fp_rdi _EXFUN(fpsetroundtoi,(fp_rdi)); -#undef isnan -#undef isinf - -int _EXFUN(isnan, (double)); -int _EXFUN(isinf, (double)); -int _EXFUN(finite, (double)); - - - -int _EXFUN(isnanf, (float)); -int _EXFUN(isinff, (float)); -int _EXFUN(finitef, (float)); - #define __IEEE_DBL_EXPBIAS 1023 #define __IEEE_FLT_EXPBIAS 127 @@ -213,22 +257,17 @@ int _EXFUN(finitef, (float)); #define __IEEE_DBL_NAN_EXP 0x7ff #define __IEEE_FLT_NAN_EXP 0xff -#ifndef __ieeefp_isnanf -#define __ieeefp_isnanf(x) (((*(long *)&(x) & 0x7f800000L)==0x7f800000L) && \ - ((*(long *)&(x) & 0x007fffffL)!=0000000000L)) -#endif +#ifdef __ieeefp_isnanf #define isnanf(x) __ieeefp_isnanf(x) - -#ifndef __ieeefp_isinff -#define __ieeefp_isinff(x) (((*(long *)&(x) & 0x7f800000L)==0x7f800000L) && \ - ((*(long *)&(x) & 0x007fffffL)==0000000000L)) #endif + +#ifdef __ieeefp_isinff #define isinff(x) __ieeefp_isinff(x) - -#ifndef __ieeefp_finitef -#define __ieeefp_finitef(x) (((*(long *)&(x) & 0x7f800000L)!=0x7f800000L)) #endif + +#ifdef __ieeefp_finitef #define finitef(x) __ieeefp_finitef(x) +#endif #ifdef _DOUBLE_IS_32BITS #undef __IEEE_DBL_EXPBIAS diff --git a/libc/xtensa-lx106-elf/include/inttypes.h b/libc/xtensa-lx106-elf/include/inttypes.h index 39bf135..694ba8f 100644 --- a/libc/xtensa-lx106-elf/include/inttypes.h +++ b/libc/xtensa-lx106-elf/include/inttypes.h @@ -14,15 +14,23 @@ #define _INTTYPES_H #include +#include #include +#include "_ansi.h" #include #define __need_wchar_t #include +#if __BSD_VISIBLE +#include +#endif + #define __STRINGIFY(a) #a /* 8-bit types */ -#define __PRI8(x) __STRINGIFY(x) +#define __PRI8(x) __INT8 __STRINGIFY(x) +#define __PRI8LEAST(x) __LEAST8 __STRINGIFY(x) +#define __PRI8FAST(x) __FAST8 __STRINGIFY(x) /* NOTICE: scanning 8-bit types requires use of the hh specifier * which is only supported on newlib platforms that @@ -35,7 +43,9 @@ */ #if defined(_WANT_IO_C99_FORMATS) - #define __SCN8(x) __STRINGIFY(hh##x) + #define __SCN8(x) __INT8 __STRINGIFY(x) + #define __SCN8LEAST(x) __LEAST8 __STRINGIFY(x) + #define __SCN8FAST(x) __FAST8 __STRINGIFY(x) #endif /* _WANT_IO_C99_FORMATS */ @@ -58,45 +68,49 @@ #endif /* _WANT_IO_C99_FORMATS */ -#define PRIdLEAST8 __PRI8(d) -#define PRIiLEAST8 __PRI8(i) -#define PRIoLEAST8 __PRI8(o) -#define PRIuLEAST8 __PRI8(u) -#define PRIxLEAST8 __PRI8(x) -#define PRIXLEAST8 __PRI8(X) +#define PRIdLEAST8 __PRI8LEAST(d) +#define PRIiLEAST8 __PRI8LEAST(i) +#define PRIoLEAST8 __PRI8LEAST(o) +#define PRIuLEAST8 __PRI8LEAST(u) +#define PRIxLEAST8 __PRI8LEAST(x) +#define PRIXLEAST8 __PRI8LEAST(X) /* Macros below are only enabled for a newlib built with C99 I/O format support. */ #if defined(_WANT_IO_C99_FORMATS) - #define SCNdLEAST8 __SCN8(d) - #define SCNiLEAST8 __SCN8(i) - #define SCNoLEAST8 __SCN8(o) - #define SCNuLEAST8 __SCN8(u) - #define SCNxLEAST8 __SCN8(x) + #define SCNdLEAST8 __SCN8LEAST(d) + #define SCNiLEAST8 __SCN8LEAST(i) + #define SCNoLEAST8 __SCN8LEAST(o) + #define SCNuLEAST8 __SCN8LEAST(u) + #define SCNxLEAST8 __SCN8LEAST(x) #endif /* _WANT_IO_C99_FORMATS */ -#define PRIdFAST8 __PRI8(d) -#define PRIiFAST8 __PRI8(i) -#define PRIoFAST8 __PRI8(o) -#define PRIuFAST8 __PRI8(u) -#define PRIxFAST8 __PRI8(x) -#define PRIXFAST8 __PRI8(X) +#define PRIdFAST8 __PRI8FAST(d) +#define PRIiFAST8 __PRI8FAST(i) +#define PRIoFAST8 __PRI8FAST(o) +#define PRIuFAST8 __PRI8FAST(u) +#define PRIxFAST8 __PRI8FAST(x) +#define PRIXFAST8 __PRI8FAST(X) /* Macros below are only enabled for a newlib built with C99 I/O format support. */ #if defined(_WANT_IO_C99_FORMATS) - #define SCNdFAST8 __SCN8(d) - #define SCNiFAST8 __SCN8(i) - #define SCNoFAST8 __SCN8(o) - #define SCNuFAST8 __SCN8(u) - #define SCNxFAST8 __SCN8(x) + #define SCNdFAST8 __SCN8FAST(d) + #define SCNiFAST8 __SCN8FAST(i) + #define SCNoFAST8 __SCN8FAST(o) + #define SCNuFAST8 __SCN8FAST(u) + #define SCNxFAST8 __SCN8FAST(x) #endif /* _WANT_IO_C99_FORMATS */ /* 16-bit types */ -#define __PRI16(x) __STRINGIFY(x) -#define __SCN16(x) __STRINGIFY(h##x) +#define __PRI16(x) __INT16 __STRINGIFY(x) +#define __PRI16LEAST(x) __LEAST16 __STRINGIFY(x) +#define __PRI16FAST(x) __FAST16 __STRINGIFY(x) +#define __SCN16(x) __INT16 __STRINGIFY(x) +#define __SCN16LEAST(x) __LEAST16 __STRINGIFY(x) +#define __SCN16FAST(x) __FAST16 __STRINGIFY(x) #define PRId16 __PRI16(d) @@ -113,41 +127,40 @@ #define SCNx16 __SCN16(x) -#define PRIdLEAST16 __PRI16(d) -#define PRIiLEAST16 __PRI16(i) -#define PRIoLEAST16 __PRI16(o) -#define PRIuLEAST16 __PRI16(u) -#define PRIxLEAST16 __PRI16(x) -#define PRIXLEAST16 __PRI16(X) +#define PRIdLEAST16 __PRI16LEAST(d) +#define PRIiLEAST16 __PRI16LEAST(i) +#define PRIoLEAST16 __PRI16LEAST(o) +#define PRIuLEAST16 __PRI16LEAST(u) +#define PRIxLEAST16 __PRI16LEAST(x) +#define PRIXLEAST16 __PRI16LEAST(X) -#define SCNdLEAST16 __SCN16(d) -#define SCNiLEAST16 __SCN16(i) -#define SCNoLEAST16 __SCN16(o) -#define SCNuLEAST16 __SCN16(u) -#define SCNxLEAST16 __SCN16(x) +#define SCNdLEAST16 __SCN16LEAST(d) +#define SCNiLEAST16 __SCN16LEAST(i) +#define SCNoLEAST16 __SCN16LEAST(o) +#define SCNuLEAST16 __SCN16LEAST(u) +#define SCNxLEAST16 __SCN16LEAST(x) -#define PRIdFAST16 __PRI16(d) -#define PRIiFAST16 __PRI16(i) -#define PRIoFAST16 __PRI16(o) -#define PRIuFAST16 __PRI16(u) -#define PRIxFAST16 __PRI16(x) -#define PRIXFAST16 __PRI16(X) +#define PRIdFAST16 __PRI16FAST(d) +#define PRIiFAST16 __PRI16FAST(i) +#define PRIoFAST16 __PRI16FAST(o) +#define PRIuFAST16 __PRI16FAST(u) +#define PRIxFAST16 __PRI16FAST(x) +#define PRIXFAST16 __PRI16FAST(X) -#define SCNdFAST16 __SCN16(d) -#define SCNiFAST16 __SCN16(i) -#define SCNoFAST16 __SCN16(o) -#define SCNuFAST16 __SCN16(u) -#define SCNxFAST16 __SCN16(x) +#define SCNdFAST16 __SCN16FAST(d) +#define SCNiFAST16 __SCN16FAST(i) +#define SCNoFAST16 __SCN16FAST(o) +#define SCNuFAST16 __SCN16FAST(u) +#define SCNxFAST16 __SCN16FAST(x) /* 32-bit types */ -#if __have_long32 -#define __PRI32(x) __STRINGIFY(l##x) -#define __SCN32(x) __STRINGIFY(l##x) -#else -#define __PRI32(x) __STRINGIFY(x) -#define __SCN32(x) __STRINGIFY(x) -#endif +#define __PRI32(x) __INT32 __STRINGIFY(x) +#define __SCN32(x) __INT32 __STRINGIFY(x) +#define __PRI32LEAST(x) __LEAST32 __STRINGIFY(x) +#define __SCN32LEAST(x) __LEAST32 __STRINGIFY(x) +#define __PRI32FAST(x) __FAST32 __STRINGIFY(x) +#define __SCN32FAST(x) __FAST32 __STRINGIFY(x) #define PRId32 __PRI32(d) #define PRIi32 __PRI32(i) @@ -163,46 +176,44 @@ #define SCNx32 __SCN32(x) -#define PRIdLEAST32 __PRI32(d) -#define PRIiLEAST32 __PRI32(i) -#define PRIoLEAST32 __PRI32(o) -#define PRIuLEAST32 __PRI32(u) -#define PRIxLEAST32 __PRI32(x) -#define PRIXLEAST32 __PRI32(X) +#define PRIdLEAST32 __PRI32LEAST(d) +#define PRIiLEAST32 __PRI32LEAST(i) +#define PRIoLEAST32 __PRI32LEAST(o) +#define PRIuLEAST32 __PRI32LEAST(u) +#define PRIxLEAST32 __PRI32LEAST(x) +#define PRIXLEAST32 __PRI32LEAST(X) -#define SCNdLEAST32 __SCN32(d) -#define SCNiLEAST32 __SCN32(i) -#define SCNoLEAST32 __SCN32(o) -#define SCNuLEAST32 __SCN32(u) -#define SCNxLEAST32 __SCN32(x) +#define SCNdLEAST32 __SCN32LEAST(d) +#define SCNiLEAST32 __SCN32LEAST(i) +#define SCNoLEAST32 __SCN32LEAST(o) +#define SCNuLEAST32 __SCN32LEAST(u) +#define SCNxLEAST32 __SCN32LEAST(x) -#define PRIdFAST32 __PRI32(d) -#define PRIiFAST32 __PRI32(i) -#define PRIoFAST32 __PRI32(o) -#define PRIuFAST32 __PRI32(u) -#define PRIxFAST32 __PRI32(x) -#define PRIXFAST32 __PRI32(X) +#define PRIdFAST32 __PRI32FAST(d) +#define PRIiFAST32 __PRI32FAST(i) +#define PRIoFAST32 __PRI32FAST(o) +#define PRIuFAST32 __PRI32FAST(u) +#define PRIxFAST32 __PRI32FAST(x) +#define PRIXFAST32 __PRI32FAST(X) -#define SCNdFAST32 __SCN32(d) -#define SCNiFAST32 __SCN32(i) -#define SCNoFAST32 __SCN32(o) -#define SCNuFAST32 __SCN32(u) -#define SCNxFAST32 __SCN32(x) +#define SCNdFAST32 __SCN32FAST(d) +#define SCNiFAST32 __SCN32FAST(i) +#define SCNoFAST32 __SCN32FAST(o) +#define SCNuFAST32 __SCN32FAST(u) +#define SCNxFAST32 __SCN32FAST(x) /* 64-bit types */ -#if __have_long64 -#define __PRI64(x) __STRINGIFY(l##x) -#define __SCN64(x) __STRINGIFY(l##x) -#elif __have_longlong64 -#define __PRI64(x) __STRINGIFY(ll##x) -#define __SCN64(x) __STRINGIFY(ll##x) -#else -#define __PRI64(x) __STRINGIFY(x) -#define __SCN64(x) __STRINGIFY(x) -#endif +#define __PRI64(x) __INT64 __STRINGIFY(x) +#define __SCN64(x) __INT64 __STRINGIFY(x) +#define __PRI64LEAST(x) __LEAST64 __STRINGIFY(x) +#define __SCN64LEAST(x) __LEAST64 __STRINGIFY(x) +#define __PRI64FAST(x) __FAST64 __STRINGIFY(x) +#define __SCN64FAST(x) __FAST64 __STRINGIFY(x) + +#if __int64_t_defined #define PRId64 __PRI64(d) #define PRIi64 __PRI64(i) #define PRIo64 __PRI64(o) @@ -215,34 +226,36 @@ #define SCNo64 __SCN64(o) #define SCNu64 __SCN64(u) #define SCNx64 __SCN64(x) +#endif -#if __int64_t_defined -#define PRIdLEAST64 __PRI64(d) -#define PRIiLEAST64 __PRI64(i) -#define PRIoLEAST64 __PRI64(o) -#define PRIuLEAST64 __PRI64(u) -#define PRIxLEAST64 __PRI64(x) -#define PRIXLEAST64 __PRI64(X) +#if __int_least64_t_defined +#define PRIdLEAST64 __PRI64LEAST(d) +#define PRIiLEAST64 __PRI64LEAST(i) +#define PRIoLEAST64 __PRI64LEAST(o) +#define PRIuLEAST64 __PRI64LEAST(u) +#define PRIxLEAST64 __PRI64LEAST(x) +#define PRIXLEAST64 __PRI64LEAST(X) -#define SCNdLEAST64 __SCN64(d) -#define SCNiLEAST64 __SCN64(i) -#define SCNoLEAST64 __SCN64(o) -#define SCNuLEAST64 __SCN64(u) -#define SCNxLEAST64 __SCN64(x) +#define SCNdLEAST64 __SCN64LEAST(d) +#define SCNiLEAST64 __SCN64LEAST(i) +#define SCNoLEAST64 __SCN64LEAST(o) +#define SCNuLEAST64 __SCN64LEAST(u) +#define SCNxLEAST64 __SCN64LEAST(x) +#endif +#if __int_fast64_t_defined +#define PRIdFAST64 __PRI64FAST(d) +#define PRIiFAST64 __PRI64FAST(i) +#define PRIoFAST64 __PRI64FAST(o) +#define PRIuFAST64 __PRI64FAST(u) +#define PRIxFAST64 __PRI64FAST(x) +#define PRIXFAST64 __PRI64FAST(X) -#define PRIdFAST64 __PRI64(d) -#define PRIiFAST64 __PRI64(i) -#define PRIoFAST64 __PRI64(o) -#define PRIuFAST64 __PRI64(u) -#define PRIxFAST64 __PRI64(x) -#define PRIXFAST64 __PRI64(X) - -#define SCNdFAST64 __SCN64(d) -#define SCNiFAST64 __SCN64(i) -#define SCNoFAST64 __SCN64(o) -#define SCNuFAST64 __SCN64(u) -#define SCNxFAST64 __SCN64(x) +#define SCNdFAST64 __SCN64FAST(d) +#define SCNiFAST64 __SCN64FAST(i) +#define SCNoFAST64 __SCN64FAST(o) +#define SCNuFAST64 __SCN64FAST(u) +#define SCNxFAST64 __SCN64FAST(x) #endif /* max-bit types */ @@ -271,10 +284,10 @@ #define SCNxMAX __SCNMAX(x) /* ptr types */ -#if defined(_UINTPTR_EQ_ULONGLONG) +#if defined (_INTPTR_EQ_LONGLONG) # define __PRIPTR(x) __STRINGIFY(ll##x) # define __SCNPTR(x) __STRINGIFY(ll##x) -#elif defined(_UINTPTR_EQ_ULONG) +#elif defined (_INTPTR_EQ_LONG) # define __PRIPTR(x) __STRINGIFY(l##x) # define __SCNPTR(x) __STRINGIFY(l##x) #else @@ -301,6 +314,8 @@ typedef struct { intmax_t rem; } imaxdiv_t; +struct _reent; + #ifdef __cplusplus extern "C" { #endif @@ -308,9 +323,20 @@ extern "C" { extern intmax_t imaxabs(intmax_t j); extern imaxdiv_t imaxdiv(intmax_t numer, intmax_t denomer); extern intmax_t strtoimax(const char *__restrict, char **__restrict, int); +extern intmax_t _strtoimax_r(struct _reent *, const char *__restrict, char **__restrict, int); extern uintmax_t strtoumax(const char *__restrict, char **__restrict, int); +extern uintmax_t _strtoumax_r(struct _reent *, const char *__restrict, char **__restrict, int); extern intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int); +extern intmax_t _wcstoimax_r(struct _reent *, const wchar_t *__restrict, wchar_t **__restrict, int); extern uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int); +extern uintmax_t _wcstoumax_r(struct _reent *, const wchar_t *__restrict, wchar_t **__restrict, int); + +#if __BSD_VISIBLE +extern intmax_t strtoimax_l(const char *__restrict, char **_restrict, int, locale_t); +extern uintmax_t strtoumax_l(const char *__restrict, char **_restrict, int, locale_t); +extern intmax_t wcstoimax_l(const wchar_t *__restrict, wchar_t **_restrict, int, locale_t); +extern uintmax_t wcstoumax_l(const wchar_t *__restrict, wchar_t **_restrict, int, locale_t); +#endif #ifdef __cplusplus } diff --git a/libc/xtensa-lx106-elf/include/langinfo.h b/libc/xtensa-lx106-elf/include/langinfo.h index 9040ade..59381d6 100644 --- a/libc/xtensa-lx106-elf/include/langinfo.h +++ b/libc/xtensa-lx106-elf/include/langinfo.h @@ -32,6 +32,9 @@ #include #include #include +#if __POSIX_VISIBLE >= 200809 +#include +#endif typedef int nl_item; @@ -301,7 +304,7 @@ enum __nl_item _NL_COLLATE_CODESET, /* This MUST be the last entry since it's used to check for an array - index in nl_langinfo(). */ + index in nl_langinfo(). It also must not exceed _NL_LOCALE_NAME_BASE. */ _NL_LOCALE_EXTENDED_LAST_ENTRY #endif /* __HAVE_LOCALE_INFO_EXTENDED__ */ @@ -309,8 +312,19 @@ enum __nl_item }; +/* As an extension, nl_langinfo can retrive the name of a locale + category, with this mapping from setlocale() category (other than + LC_ALL) to nl_item. */ +#define _NL_LOCALE_NAME_BASE 100000 +#if __GNU_VISIBLE +#define NL_LOCALE_NAME(category) (_NL_LOCALE_NAME_BASE + (category)) +#endif + __BEGIN_DECLS -char *nl_langinfo(nl_item); +char *nl_langinfo (nl_item); +#if __POSIX_VISIBLE >= 200809 +char *nl_langinfo_l (nl_item, locale_t); +#endif __END_DECLS #endif /* !_LANGINFO_H_ */ diff --git a/libc/xtensa-lx106-elf/include/libgen.h b/libc/xtensa-lx106-elf/include/libgen.h index abfab0e..3c717c5 100644 --- a/libc/xtensa-lx106-elf/include/libgen.h +++ b/libc/xtensa-lx106-elf/include/libgen.h @@ -6,13 +6,27 @@ #define _LIBGEN_H_ #include "_ansi.h" +#include #include #ifdef __cplusplus extern "C" { #endif -char *_EXFUN(basename, (char *)); +/* There are two common basename variants. If you do NOT #include + and you do + + #define _GNU_SOURCE + #include + + you get the GNU version. Otherwise you get the POSIX versionfor which you + should #include i for the function prototype. POSIX requires that + #undef basename will still let you invoke the underlying function. However, + this also implies that the POSIX version is used in this case. That's made + sure here. */ +#undef basename +#define basename __xpg_basename +char *_EXFUN(basename, (char *)) __asm__(__ASMNAME("basename")); char *_EXFUN(dirname, (char *)); #ifdef __cplusplus diff --git a/libc/xtensa-lx106-elf/include/limits.h b/libc/xtensa-lx106-elf/include/limits.h index 190f1f7..dd09c1c 100644 --- a/libc/xtensa-lx106-elf/include/limits.h +++ b/libc/xtensa-lx106-elf/include/limits.h @@ -2,6 +2,7 @@ # define _LIBC_LIMITS_H_ 1 #include +#include # ifdef _MB_LEN_MAX # define MB_LEN_MAX _MB_LEN_MAX @@ -96,8 +97,7 @@ # define __LONG_LONG_MAX__ 9223372036854775807LL # endif -# if (defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +# if __ISO_C_VISIBLE >= 1999 /* Minimum and maximum values a `signed long long int' can hold. */ # undef LLONG_MIN # define LLONG_MIN (-LLONG_MAX-1) @@ -109,7 +109,7 @@ # define ULLONG_MAX (LLONG_MAX * 2ULL + 1) # endif -# if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__) +# if __GNU_VISIBLE /* Minimum and maximum values a `signed long long int' can hold. */ # undef LONG_LONG_MIN # define LONG_LONG_MIN (-LONG_LONG_MAX-1) diff --git a/libc/xtensa-lx106-elf/include/locale.h b/libc/xtensa-lx106-elf/include/locale.h index cbd658e..8ba88a9 100644 --- a/libc/xtensa-lx106-elf/include/locale.h +++ b/libc/xtensa-lx106-elf/include/locale.h @@ -8,6 +8,7 @@ #define _LOCALE_H_ #include "_ansi.h" +#include #define __need_NULL #include @@ -20,6 +21,22 @@ #define LC_TIME 5 #define LC_MESSAGES 6 +#if __POSIX_VISIBLE >= 200809 || defined (_COMPILING_NEWLIB) + +#include + +#define LC_ALL_MASK (1 << LC_ALL) +#define LC_COLLATE_MASK (1 << LC_COLLATE) +#define LC_CTYPE_MASK (1 << LC_CTYPE) +#define LC_MONETARY_MASK (1 << LC_MONETARY) +#define LC_NUMERIC_MASK (1 << LC_NUMERIC) +#define LC_TIME_MASK (1 << LC_TIME) +#define LC_MESSAGES_MASK (1 << LC_MESSAGES) + +#define LC_GLOBAL_LOCALE ((struct __locale_t *) -1) + +#endif /* __POSIX_VISIBLE >= 200809 */ + _BEGIN_STD_C struct lconv @@ -50,15 +67,30 @@ struct lconv char int_p_sign_posn; }; -#ifndef _REENT_ONLY -char *_EXFUN(setlocale,(int category, const char *locale)); -struct lconv *_EXFUN(localeconv,(void)); -#endif - struct _reent; -char *_EXFUN(_setlocale_r,(struct _reent *, int category, const char *locale)); +char *_EXFUN(_setlocale_r,(struct _reent *, int, const char *)); struct lconv *_EXFUN(_localeconv_r,(struct _reent *)); +struct __locale_t *_newlocale_r (struct _reent *, int, const char *, + struct __locale_t *); +void _freelocale_r (struct _reent *, struct __locale_t *); +struct __locale_t *_duplocale_r (struct _reent *, struct __locale_t *); +struct __locale_t *_uselocale_r (struct _reent *, struct __locale_t *); + +#ifndef _REENT_ONLY + +char *_EXFUN(setlocale,(int, const char *)); +struct lconv *_EXFUN(localeconv,(void)); + +#if __POSIX_VISIBLE >= 200809 +locale_t newlocale (int, const char *, locale_t); +void freelocale (locale_t); +locale_t duplocale (locale_t); +locale_t uselocale (locale_t); +#endif /* __POSIX_VISIBLE >= 200809 */ + +#endif /* _REENT_ONLY */ + _END_STD_C #endif /* _LOCALE_H_ */ diff --git a/libc/xtensa-lx106-elf/include/machine/_arc4random.h b/libc/xtensa-lx106-elf/include/machine/_arc4random.h new file mode 100644 index 0000000..52808d7 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/machine/_arc4random.h @@ -0,0 +1 @@ +/* Use default implementation, see arc4random.h */ diff --git a/libc/xtensa-lx106-elf/include/machine/_default_types.h b/libc/xtensa-lx106-elf/include/machine/_default_types.h index 03bdc52..59552f5 100644 --- a/libc/xtensa-lx106-elf/include/machine/_default_types.h +++ b/libc/xtensa-lx106-elf/include/machine/_default_types.h @@ -46,6 +46,9 @@ typedef __int64_t __int_least64_t; typedef __uint64_t __uint_least64_t; #define ___int_least64_t_defined +typedef __int64_t __intmax_t; +typedef __uint64_t __uintmax_t; + typedef __INTPTR_TYPE__ __intptr_t; typedef __UINTPTR_TYPE__ __uintptr_t; diff --git a/libc/xtensa-lx106-elf/include/machine/_endian.h b/libc/xtensa-lx106-elf/include/machine/_endian.h new file mode 100644 index 0000000..92a14dc --- /dev/null +++ b/libc/xtensa-lx106-elf/include/machine/_endian.h @@ -0,0 +1,35 @@ +#ifndef __MACHINE_ENDIAN_H__ +#error "must be included via " +#endif /* !__MACHINE_ENDIAN_H__ */ + +#include + +#ifdef __PPC__ +/* Get rid of GCC builtin defines on PowerPC */ +#ifdef _BIG_ENDIAN +#undef _BIG_ENDIAN +#endif +#ifdef _LITTLE_ENDIAN +#undef _LITTLE_ENDIAN +#endif +#endif /* __PPC__ */ + +#ifndef _LITTLE_ENDIAN +#define _LITTLE_ENDIAN 1234 +#endif + +#ifndef _BIG_ENDIAN +#define _BIG_ENDIAN 4321 +#endif + +#ifndef _PDP_ENDIAN +#define _PDP_ENDIAN 3412 +#endif + +#ifndef _BYTE_ORDER +#if defined(__IEEE_LITTLE_ENDIAN) || defined(__IEEE_BYTES_LITTLE_ENDIAN) +#define _BYTE_ORDER _LITTLE_ENDIAN +#else +#define _BYTE_ORDER _BIG_ENDIAN +#endif +#endif diff --git a/libc/xtensa-lx106-elf/include/machine/_time.h b/libc/xtensa-lx106-elf/include/machine/_time.h new file mode 100644 index 0000000..476760c --- /dev/null +++ b/libc/xtensa-lx106-elf/include/machine/_time.h @@ -0,0 +1,3 @@ +#ifndef _SYS_TIME_H_ +#error "must be included via " +#endif /* !_SYS_TIME_H_ */ diff --git a/libc/xtensa-lx106-elf/include/machine/endian.h b/libc/xtensa-lx106-elf/include/machine/endian.h index 07ebc8f..34a5726 100644 --- a/libc/xtensa-lx106-elf/include/machine/endian.h +++ b/libc/xtensa-lx106-elf/include/machine/endian.h @@ -1,20 +1,69 @@ #ifndef __MACHINE_ENDIAN_H__ +#define __MACHINE_ENDIAN_H__ -#include +#include +#include +#include -#ifndef BIG_ENDIAN -#define BIG_ENDIAN 4321 -#endif -#ifndef LITTLE_ENDIAN -#define LITTLE_ENDIAN 1234 -#endif - -#ifndef BYTE_ORDER -#if defined(__IEEE_LITTLE_ENDIAN) || defined(__IEEE_BYTES_LITTLE_ENDIAN) -#define BYTE_ORDER LITTLE_ENDIAN +#if _BYTE_ORDER == _LITTLE_ENDIAN +#define _QUAD_HIGHWORD 1 +#define _QUAD_LOWWORD 0 #else -#define BYTE_ORDER BIG_ENDIAN +#define _QUAD_HIGHWORD 0 +#define _QUAD_LOWWORD 1 #endif + +#if __BSD_VISIBLE +#define LITTLE_ENDIAN _LITTLE_ENDIAN +#define BIG_ENDIAN _BIG_ENDIAN +#define PDP_ENDIAN _PDP_ENDIAN +#define BYTE_ORDER _BYTE_ORDER #endif +#ifdef __GNUC__ +#define __bswap16(_x) __builtin_bswap16(_x) +#define __bswap32(_x) __builtin_bswap32(_x) +#define __bswap64(_x) __builtin_bswap64(_x) +#else /* __GNUC__ */ +static __inline __uint16_t +__bswap16(__uint16_t _x) +{ + + return ((__uint16_t)((_x >> 8) | ((_x << 8) & 0xff00))); +} + +static __inline __uint32_t +__bswap32(__uint32_t _x) +{ + + return ((__uint32_t)((_x >> 24) | ((_x >> 8) & 0xff00) | + ((_x << 8) & 0xff0000) | ((_x << 24) & 0xff000000))); +} + +static __inline __uint64_t +__bswap64(__uint64_t _x) +{ + + return ((__uint64_t)((_x >> 56) | ((_x >> 40) & 0xff00) | + ((_x >> 24) & 0xff0000) | ((_x >> 8) & 0xff000000) | + ((_x << 8) & ((__uint64_t)0xff << 32)) | + ((_x << 24) & ((__uint64_t)0xff << 40)) | + ((_x << 40) & ((__uint64_t)0xff << 48)) | ((_x << 56)))); +} +#endif /* !__GNUC__ */ + +#ifndef __machine_host_to_from_network_defined +#if _BYTE_ORDER == _LITTLE_ENDIAN +#define __htonl(_x) __bswap32(_x) +#define __htons(_x) __bswap16(_x) +#define __ntohl(_x) __bswap32(_x) +#define __ntohs(_x) __bswap16(_x) +#else +#define __htonl(_x) ((__uint32_t)(_x)) +#define __htons(_x) ((__uint16_t)(_x)) +#define __ntohl(_x) ((__uint32_t)(_x)) +#define __ntohs(_x) ((__uint16_t)(_x)) +#endif +#endif /* __machine_host_to_from_network_defined */ + #endif /* __MACHINE_ENDIAN_H__ */ diff --git a/libc/xtensa-lx106-elf/include/machine/ieeefp.h b/libc/xtensa-lx106-elf/include/machine/ieeefp.h index f11dc05..23c03a7 100644 --- a/libc/xtensa-lx106-elf/include/machine/ieeefp.h +++ b/libc/xtensa-lx106-elf/include/machine/ieeefp.h @@ -170,6 +170,10 @@ #define __IEEE_LITTLE_ENDIAN #endif +#ifdef __riscv +#define __IEEE_LITTLE_ENDIAN +#endif + #ifdef __i960__ #define __IEEE_LITTLE_ENDIAN #endif @@ -283,6 +287,10 @@ #define __IEEE_BIG_ENDIAN #endif +#ifdef __FT32__ +#define __IEEE_LITTLE_ENDIAN +#endif + #ifdef __mcore__ #define __IEEE_BIG_ENDIAN #endif @@ -415,6 +423,10 @@ # endif #endif +#ifdef __VISIUM__ +#define __IEEE_BIG_ENDIAN +#endif + #if (defined(__XTENSA__)) # ifdef __XTENSA_EB__ # define __IEEE_BIG_ENDIAN diff --git a/libc/xtensa-lx106-elf/include/machine/setjmp.h b/libc/xtensa-lx106-elf/include/machine/setjmp.h index 9f9d9e4..d93636b 100644 --- a/libc/xtensa-lx106-elf/include/machine/setjmp.h +++ b/libc/xtensa-lx106-elf/include/machine/setjmp.h @@ -92,6 +92,9 @@ _BEGIN_STD_C # define _JBLEN (13 * 4) # elif defined(__unix__) || defined(__rtems__) # define _JBLEN 9 +# elif defined(__iamcu__) +/* Intel MCU jmp_buf only covers callee-saved registers. */ +# define _JBLEN 6 # else # include "setjmp-dj.h" # endif @@ -250,6 +253,10 @@ _BEGIN_STD_C #define _JBLEN 10 #endif +#ifdef __FT32__ +#define _JBLEN 27 +#endif + #ifdef __iq2000__ #define _JBLEN 32 #endif @@ -258,6 +265,10 @@ _BEGIN_STD_C #define _JBLEN 16 #endif +#ifdef __arc__ +#define _JBLEN 25 /* r13-r30,blink,lp_count,lp_start,lp_end,mlo,mhi,status32 */ +#endif + #ifdef __MMIX__ /* Using a layout compatible with GCC's built-in. */ #define _JBLEN 5 @@ -314,6 +325,10 @@ _BEGIN_STD_C #define _JBLEN 18 #endif +#ifdef __ia64 +#define _JBLEN 64 +#endif + #ifdef __lm32__ #define _JBLEN 19 #endif @@ -365,6 +380,20 @@ _BEGIN_STD_C #define _JBLEN 0x44 #endif +#ifdef __VISIUM__ +/* All call-saved GP registers: r11-r19,r21,r22,r23. */ +#define _JBLEN 12 +#endif + +#ifdef __riscv +#define _JBTYPE long +#ifdef __riscv_32e +#define _JBLEN ((4*sizeof(long))/sizeof(long)) +#else +#define _JBLEN ((14*sizeof(long) + 12*sizeof(double))/sizeof(long)) +#endif +#endif + #ifdef _JBLEN #ifdef _JBTYPE typedef _JBTYPE jmp_buf[_JBLEN]; @@ -375,7 +404,7 @@ typedef int jmp_buf[_JBLEN]; _END_STD_C -#if defined(__CYGWIN__) || defined(__rtems__) +#if (defined(__CYGWIN__) || defined(__rtems__)) && __POSIX_VISIBLE #include #ifdef __cplusplus @@ -403,6 +432,13 @@ typedef int sigjmp_buf[_JBLEN+1+(sizeof (sigset_t)/sizeof (int))]; #define __SIGMASK_FUNC sigprocmask #endif +#ifdef __CYGWIN__ +/* Per POSIX, siglongjmp has to be implemented as function. Cygwin + provides functions for both, siglongjmp and sigsetjmp since 2.2.0. */ +extern void siglongjmp (sigjmp_buf, int) __attribute__ ((__noreturn__)); +extern int sigsetjmp (sigjmp_buf, int); +#endif + #if defined(__GNUC__) #define sigsetjmp(env, savemask) \ @@ -440,8 +476,8 @@ typedef int sigjmp_buf[_JBLEN+1+(sizeof (sigset_t)/sizeof (int))]; are equivalent to sigsetjmp/siglongjmp when not saving the signal mask. New applications should use sigsetjmp/siglongjmp instead. */ #ifdef __CYGWIN__ -extern void _longjmp(jmp_buf, int); -extern int _setjmp(jmp_buf); +extern void _longjmp (jmp_buf, int) __attribute__ ((__noreturn__)); +extern int _setjmp (jmp_buf); #else #define _setjmp(env) sigsetjmp ((env), 0) #define _longjmp(env, val) siglongjmp ((env), (val)) @@ -450,4 +486,4 @@ extern int _setjmp(jmp_buf); #ifdef __cplusplus } #endif -#endif /* __CYGWIN__ or __rtems__ */ +#endif /* (__CYGWIN__ or __rtems__) and __POSIX_VISIBLE */ diff --git a/libc/xtensa-lx106-elf/include/machine/time.h b/libc/xtensa-lx106-elf/include/machine/time.h index 06e2ccf..c75edaf 100644 --- a/libc/xtensa-lx106-elf/include/machine/time.h +++ b/libc/xtensa-lx106-elf/include/machine/time.h @@ -1,19 +1,15 @@ #ifndef _MACHTIME_H_ #define _MACHTIME_H_ -#if defined(__rtems__) -#define _CLOCKS_PER_SEC_ sysconf(_SC_CLK_TCK) -#else /* !__rtems__ */ -#if defined(__aarch64__) || defined(__arm__) || defined(__thumb__) +#if defined(__rtems__) || defined(__VISIUM__) || defined(__riscv) +#define _CLOCKS_PER_SEC_ 1000000 +#elif defined(__aarch64__) || defined(__arm__) || defined(__thumb__) #define _CLOCKS_PER_SEC_ 100 #endif -#endif /* !__rtems__ */ #ifdef __SPU__ -#include +#include int nanosleep (const struct timespec *, struct timespec *); #endif #endif /* _MACHTIME_H_ */ - - diff --git a/libc/xtensa-lx106-elf/include/machine/types.h b/libc/xtensa-lx106-elf/include/machine/types.h index 40a75fa..a5a64e6 100644 --- a/libc/xtensa-lx106-elf/include/machine/types.h +++ b/libc/xtensa-lx106-elf/include/machine/types.h @@ -1,30 +1,7 @@ -#ifndef _MACHTYPES_H_ -#define _MACHTYPES_H_ - /* - * The following section is RTEMS specific and is needed to more - * closely match the types defined in the BSD machine/types.h. - * This is needed to let the RTEMS/BSD TCP/IP stack compile. + * Newlib targets may provide an own version of this file in their machine + * directory to add custom user types for . */ -#if defined(__rtems__) -#include -#endif - -#define _CLOCK_T_ unsigned long /* clock() */ -#define _TIME_T_ long /* time() */ -#define _CLOCKID_T_ unsigned long -#define _TIMER_T_ unsigned long - -#ifndef _HAVE_SYSTYPES -typedef long int __off_t; -typedef int __pid_t; -#ifdef __GNUC__ -__extension__ typedef long long int __loff_t; -#else -typedef long int __loff_t; -#endif -#endif - -#endif /* _MACHTYPES_H_ */ - - +#ifndef _SYS_TYPES_H +#error "must be included via " +#endif /* !_SYS_TYPES_H */ diff --git a/libc/xtensa-lx106-elf/include/math.h b/libc/xtensa-lx106-elf/include/math.h index d16ce30..2a322ee 100644 --- a/libc/xtensa-lx106-elf/include/math.h +++ b/libc/xtensa-lx106-elf/include/math.h @@ -3,34 +3,12 @@ #define _MATH_H_ #include +#include #include #include "_ansi.h" _BEGIN_STD_C -/* __dmath, __fmath, and __ldmath are only here for backwards compatibility - * in case any code used them. They are no longer used by Newlib, itself, - * other than legacy. */ -union __dmath -{ - double d; - __ULong i[2]; -}; - -union __fmath -{ - float f; - __ULong i[1]; -}; - -#if defined(_HAVE_LONG_DOUBLE) -union __ldmath -{ - long double ld; - __ULong i[4]; -}; -#endif - /* Natural log of 2 */ #define _M_LN2 0.693147180559945309417 @@ -136,9 +114,26 @@ extern double fmod _PARAMS((double, double)); #endif /* ! defined (__math_68881) */ #endif /* ! defined (_REENT_ONLY) */ -#if !defined(__STRICT_ANSI__) || defined(__cplusplus) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) +#if __MISC_VISIBLE +extern int finite _PARAMS((double)); +extern int finitef _PARAMS((float)); +extern int finitel _PARAMS((long double)); +extern int isinff _PARAMS((float)); +extern int isnanf _PARAMS((float)); +#ifdef __CYGWIN__ /* not implemented in newlib yet */ +extern int isinfl _PARAMS((long double)); +extern int isnanl _PARAMS((long double)); +#endif +#if !defined(__cplusplus) || __cplusplus < 201103L +extern int isinf _PARAMS((double)); +#endif +#endif /* __MISC_VISIBLE */ +#if (__MISC_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 600)) \ + && (!defined(__cplusplus) || __cplusplus < 201103L) +extern int isnan _PARAMS((double)); +#endif +#if __ISO_C_VISIBLE >= 1999 /* ISO C99 types and macros. */ /* FIXME: FLT_EVAL_METHOD should somehow be gotten from float.h (which is hard, @@ -180,10 +175,10 @@ extern double fmod _PARAMS((double, double)); #define FP_NORMAL 4 #ifndef FP_ILOGB0 -# define FP_ILOGB0 (-INT_MAX) +# define FP_ILOGB0 (-__INT_MAX__) #endif #ifndef FP_ILOGBNAN -# define FP_ILOGBNAN INT_MAX +# define FP_ILOGBNAN __INT_MAX__ #endif #ifndef MATH_ERRNO @@ -205,35 +200,70 @@ extern int __fpclassifyd (double x); extern int __signbitf (float x); extern int __signbitd (double x); -#define fpclassify(__x) \ - ((sizeof(__x) == sizeof(float)) ? __fpclassifyf(__x) : \ - __fpclassifyd(__x)) - -#ifndef isfinite - #define isfinite(__y) \ - (__extension__ ({int __cy = fpclassify(__y); \ - __cy != FP_INFINITE && __cy != FP_NAN;})) -#endif - /* Note: isinf and isnan were once functions in newlib that took double * arguments. C99 specifies that these names are reserved for macros * supporting multiple floating point types. Thus, they are * now defined as macros. Implementations of the old functions * taking double arguments still exist for compatibility purposes - * (prototypes for them are in ). */ -#ifndef isinf - #define isinf(y) (fpclassify(y) == FP_INFINITE) + * (prototypes for them are earlier in this header). */ + +#if __GNUC_PREREQ (4, 4) + #define fpclassify(__x) (__builtin_fpclassify (FP_NAN, FP_INFINITE, \ + FP_NORMAL, FP_SUBNORMAL, \ + FP_ZERO, __x)) + #ifndef isfinite + #define isfinite(__x) (__builtin_isfinite (__x)) + #endif + #ifndef isinf + #define isinf(__x) (__builtin_isinf_sign (__x)) + #endif + #ifndef isnan + #define isnan(__x) (__builtin_isnan (__x)) + #endif + #define isnormal(__x) (__builtin_isnormal (__x)) +#else + #define fpclassify(__x) \ + ((sizeof(__x) == sizeof(float)) ? __fpclassifyf(__x) : \ + __fpclassifyd(__x)) + #ifndef isfinite + #define isfinite(__y) \ + (__extension__ ({int __cy = fpclassify(__y); \ + __cy != FP_INFINITE && __cy != FP_NAN;})) + #endif + #ifndef isinf + #define isinf(__x) (fpclassify(__x) == FP_INFINITE) + #endif + #ifndef isnan + #define isnan(__x) (fpclassify(__x) == FP_NAN) + #endif + #define isnormal(__x) (fpclassify(__x) == FP_NORMAL) #endif -#ifndef isnan - #define isnan(y) (fpclassify(y) == FP_NAN) +#if __GNUC_PREREQ (4, 0) + #if defined(_HAVE_LONG_DOUBLE) + #define signbit(__x) \ + ((sizeof(__x) == sizeof(float)) ? __builtin_signbitf(__x) : \ + (sizeof(__x) == sizeof(double)) ? __builtin_signbit (__x) : \ + __builtin_signbitl(__x)) + #else + #define signbit(__x) \ + ((sizeof(__x) == sizeof(float)) ? __builtin_signbitf(__x) : \ + __builtin_signbit (__x)) + #endif +#else + #define signbit(__x) \ + ((sizeof(__x) == sizeof(float)) ? __signbitf(__x) : \ + __signbitd(__x)) #endif -#define isnormal(y) (fpclassify(y) == FP_NORMAL) -#define signbit(__x) \ - ((sizeof(__x) == sizeof(float)) ? __signbitf(__x) : \ - __signbitd(__x)) - +#if __GNUC_PREREQ (2, 97) +#define isgreater(__x,__y) (__builtin_isgreater (__x, __y)) +#define isgreaterequal(__x,__y) (__builtin_isgreaterequal (__x, __y)) +#define isless(__x,__y) (__builtin_isless (__x, __y)) +#define islessequal(__x,__y) (__builtin_islessequal (__x, __y)) +#define islessgreater(__x,__y) (__builtin_islessgreater (__x, __y)) +#define isunordered(__x,__y) (__builtin_isunordered (__x, __y)) +#else #define isgreater(x,y) \ (__extension__ ({__typeof__(x) __x = (x); __typeof__(y) __y = (y); \ !isunordered(__x,__y) && (__x > __y);})) @@ -253,12 +283,12 @@ extern int __signbitd (double x); #define isunordered(a,b) \ (__extension__ ({__typeof__(a) __a = (a); __typeof__(b) __b = (b); \ fpclassify(__a) == FP_NAN || fpclassify(__b) == FP_NAN;})) +#endif /* Non ANSI double precision functions. */ extern double infinity _PARAMS((void)); extern double nan _PARAMS((const char *)); -extern int finite _PARAMS((double)); extern double copysign _PARAMS((double, double)); extern double logb _PARAMS((double)); extern int ilogb _PARAMS((double)); @@ -357,7 +387,6 @@ extern float fmaf _PARAMS((float, float, float)); extern float infinityf _PARAMS((void)); extern float nanf _PARAMS((const char *)); -extern int finitef _PARAMS((float)); extern float copysignf _PARAMS((float, float)); extern float logbf _PARAMS((float)); extern int ilogbf _PARAMS((float)); @@ -382,8 +411,12 @@ extern float log2f _PARAMS((float)); extern float hypotf _PARAMS((float, float)); #endif /* ! defined (_REENT_ONLY) */ -/* On platforms where long double equals double. */ -#ifdef _LDBL_EQ_DBL +/* Newlib doesn't fully support long double math functions so far. + On platforms where long double equals double the long double functions + simply call the double functions. On Cygwin the long double functions + are implemented independently from newlib to be able to use optimized + assembler functions despite using the Microsoft x86_64 ABI. */ +#if defined (_LDBL_EQ_DBL) || defined (__CYGWIN__) /* Reentrant ANSI C functions. */ #ifndef __math_68881 extern long double atanl _PARAMS((long double)); @@ -453,44 +486,56 @@ extern long double lgammal _PARAMS((long double)); extern long double erfl _PARAMS((long double)); extern long double erfcl _PARAMS((long double)); #endif /* ! defined (_REENT_ONLY) */ -#else /* !_LDBL_EQ_DBL */ +#else /* !_LDBL_EQ_DBL && !__CYGWIN__ */ +extern long double hypotl _PARAMS((long double, long double)); +extern long double sqrtl _PARAMS((long double)); #ifdef __i386__ /* Other long double precision functions. */ extern _LONG_DOUBLE rintl _PARAMS((_LONG_DOUBLE)); extern long int lrintl _PARAMS((_LONG_DOUBLE)); extern long long int llrintl _PARAMS((_LONG_DOUBLE)); #endif /* __i386__ */ -#endif /* !_LDBL_EQ_DBL */ +#endif /* !_LDBL_EQ_DBL && !__CYGWIN__ */ -#endif /* !defined (__STRICT_ANSI__) || defined(__cplusplus) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) */ - -#if !defined (__STRICT_ANSI__) || defined(__cplusplus) +#endif /* __ISO_C_VISIBLE >= 1999 */ +#if __MISC_VISIBLE extern double drem _PARAMS((double, double)); -extern void sincos _PARAMS((double, double *, double *)); +extern float dremf _PARAMS((float, float)); +#ifdef __CYGWIN__ +extern float dreml _PARAMS((long double, long double)); +#endif /* __CYGWIN__ */ extern double gamma_r _PARAMS((double, int *)); extern double lgamma_r _PARAMS((double, int *)); +extern float gammaf_r _PARAMS((float, int *)); +extern float lgammaf_r _PARAMS((float, int *)); +#endif +#if __MISC_VISIBLE || __XSI_VISIBLE extern double y0 _PARAMS((double)); extern double y1 _PARAMS((double)); extern double yn _PARAMS((int, double)); extern double j0 _PARAMS((double)); extern double j1 _PARAMS((double)); extern double jn _PARAMS((int, double)); +#endif -extern float dremf _PARAMS((float, float)); -extern void sincosf _PARAMS((float, float *, float *)); -extern float gammaf_r _PARAMS((float, int *)); -extern float lgammaf_r _PARAMS((float, int *)); - +#if __MISC_VISIBLE || __XSI_VISIBLE >= 600 extern float y0f _PARAMS((float)); extern float y1f _PARAMS((float)); extern float ynf _PARAMS((int, float)); extern float j0f _PARAMS((float)); extern float j1f _PARAMS((float)); extern float jnf _PARAMS((int, float)); +#endif /* GNU extensions */ +#if __GNU_VISIBLE +extern void sincos _PARAMS((double, double *, double *)); +extern void sincosf _PARAMS((float, float *, float *)); +#ifdef __CYGWIN__ +extern void sincosl _PARAMS((long double, long double *, long double *)); +#endif /* __CYGWIN__ */ # ifndef exp10 extern double exp10 _PARAMS((double)); # endif @@ -503,11 +548,17 @@ extern float exp10f _PARAMS((float)); # ifndef pow10f extern float pow10f _PARAMS((float)); # endif +#ifdef __CYGWIN__ +# ifndef exp10l +extern float exp10l _PARAMS((float)); +# endif +# ifndef pow10l +extern float pow10l _PARAMS((float)); +# endif +#endif /* __CYGWIN__ */ +#endif /* __GNU_VISIBLE */ -#endif /* !defined (__STRICT_ANSI__) || defined(__cplusplus) */ - -#ifndef __STRICT_ANSI__ - +#if __MISC_VISIBLE || __XSI_VISIBLE /* The gamma functions use a global variable, signgam. */ #ifndef _REENT_ONLY #define signgam (*__signgam()) @@ -515,7 +566,9 @@ extern int *__signgam _PARAMS((void)); #endif /* ! defined (_REENT_ONLY) */ #define __signgam_r(ptr) _REENT_SIGNGAM(ptr) +#endif /* __MISC_VISIBLE || __XSI_VISIBLE */ +#if __SVID_VISIBLE /* The exception structure passed to the matherr routine. */ /* We have a problem when using C++ since `exception' is a reserved name in C++. */ @@ -548,11 +601,11 @@ extern int matherr _PARAMS((struct exception *e)); #define TLOSS 5 #define PLOSS 6 -#endif /* ! defined (__STRICT_ANSI__) */ +#endif /* __SVID_VISIBLE */ /* Useful constants. */ -#if !defined(__STRICT_ANSI__) || ((_XOPEN_SOURCE - 0) >= 500) +#if __BSD_VISIBLE || __XSI_VISIBLE #define MAXFLOAT 3.40282347e+38F @@ -572,7 +625,7 @@ extern int matherr _PARAMS((struct exception *e)); #endif -#ifndef __STRICT_ANSI__ +#if __BSD_VISIBLE #define M_TWOPI (M_PI * 2.0) #define M_3PI_4 2.3561944901923448370E0 @@ -604,7 +657,7 @@ extern __IMPORT _LIB_VERSION_TYPE _LIB_VERSION; #define _XOPEN_ __fdlibm_xopen #define _POSIX_ __fdlibm_posix -#endif /* ! defined (__STRICT_ANSI__) */ +#endif /* __BSD_VISIBLE */ _END_STD_C diff --git a/libc/xtensa-lx106-elf/include/memory.h b/libc/xtensa-lx106-elf/include/memory.h new file mode 100644 index 0000000..f4a14fc --- /dev/null +++ b/libc/xtensa-lx106-elf/include/memory.h @@ -0,0 +1,4 @@ +#ifndef _MEMORY_H +#define _MEMORY_H +#include +#endif /* !_MEMORY_H */ diff --git a/libc/xtensa-lx106-elf/include/newlib.h b/libc/xtensa-lx106-elf/include/newlib.h index e9bf566..f4dd838 100644 --- a/libc/xtensa-lx106-elf/include/newlib.h +++ b/libc/xtensa-lx106-elf/include/newlib.h @@ -11,7 +11,7 @@ /* #undef _ELIX_LEVEL */ /* Newlib version */ -#define _NEWLIB_VERSION "2.2.0" +#include <_newlib_version.h> /* C99 formats support (such as %a, %zu, ...) in IO functions like * printf/scanf enabled */ @@ -62,12 +62,6 @@ /* True if long double supported and it is equal to double. */ #define _LDBL_EQ_DBL 1 -/* Define if uintptr_t is unsigned long on this architecture */ -/* #undef _UINTPTR_EQ_ULONG */ - -/* Define if uintptr_t is unsigned long long on this architecture */ -/* #undef _UINTPTR_EQ_ULONGLONG */ - /* Define if ivo supported in streamio. */ #define _FVWRITE_IN_STREAMIO 1 @@ -86,9 +80,20 @@ /* Define if declare atexit data as global. */ /* #undef _REENT_GLOBAL_ATEXIT */ +/* Define to move the stdio stream FILE objects out of struct _reent and make + them global. The stdio stream pointers of struct _reent are initialized to + point to the global stdio FILE stream objects. */ +/* #undef _WANT_REENT_GLOBAL_STDIO_STREAMS */ + /* Define if small footprint nano-formatted-IO implementation used. */ #define _NANO_FORMATTED_IO 1 +/* Define if using retargetable functions for default lock routines. */ +/* #undef _RETARGETABLE_LOCKING */ + +/* Define to use type long for time_t. */ +/* #undef _WANT_USE_LONG_TIME_T */ + /* * Iconv encodings enabled ("to" direction) */ diff --git a/libc/xtensa-lx106-elf/include/pthread.h b/libc/xtensa-lx106-elf/include/pthread.h index db1f9c1..516131d 100644 --- a/libc/xtensa-lx106-elf/include/pthread.h +++ b/libc/xtensa-lx106-elf/include/pthread.h @@ -1,8 +1,7 @@ -/* pthread.h +/* + * Written by Joel Sherrill . * - * Written by Joel Sherrill . - * - * COPYRIGHT (c) 1989-2013. + * COPYRIGHT (c) 1989-2013, 2015. * On-Line Applications Research Corporation (OAR). * * Permission to use, copy, modify, and distribute this software for any @@ -14,8 +13,6 @@ * WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION * OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS * SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - * - * $Id$ */ #ifndef __PTHREAD_h @@ -31,7 +28,7 @@ extern "C" { #include #include -#include +#include #include struct _pthread_cleanup_context { @@ -76,7 +73,7 @@ int _EXFUN(pthread_mutex_destroy, (pthread_mutex_t *__mutex)); pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; */ -#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) 0xFFFFFFFF) +#define PTHREAD_MUTEX_INITIALIZER _PTHREAD_MUTEX_INITIALIZER /* Locking and Unlocking a Mutex, P1003.1c/Draft 10, p. 93 NOTE: P1003.4b/D8 adds pthread_mutex_timedlock(), p. 29 */ @@ -96,6 +93,13 @@ int _EXFUN(pthread_mutex_timedlock, int _EXFUN(pthread_condattr_init, (pthread_condattr_t *__attr)); int _EXFUN(pthread_condattr_destroy, (pthread_condattr_t *__attr)); + +int _EXFUN(pthread_condattr_getclock, + (const pthread_condattr_t *__restrict __attr, + clockid_t *__restrict __clock_id)); +int _EXFUN(pthread_condattr_setclock, + (pthread_condattr_t *__attr, clockid_t __clock_id)); + int _EXFUN(pthread_condattr_getpshared, (_CONST pthread_condattr_t *__attr, int *__pshared)); int _EXFUN(pthread_condattr_setpshared, @@ -112,7 +116,7 @@ int _EXFUN(pthread_cond_destroy, (pthread_cond_t *__mutex)); pthread_cond_t cond = PTHREAD_COND_INITIALIZER; */ -#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) 0xFFFFFFFF) +#define PTHREAD_COND_INITIALIZER _PTHREAD_COND_INITIALIZER /* Broadcasting and Signaling a Condition, P1003.1c/Draft 10, p. 101 */ @@ -161,8 +165,17 @@ int _EXFUN(pthread_getschedparam, int _EXFUN(pthread_setschedparam, (pthread_t __pthread, int __policy, struct sched_param *__param)); +/* Set Scheduling Priority of a Thread */ +int _EXFUN(pthread_setschedprio, (pthread_t thread, int prio)); + #endif /* defined(_POSIX_THREAD_PRIORITY_SCHEDULING) */ +#if __GNU_VISIBLE +int pthread_getname_np(pthread_t, char *, size_t) __nonnull(2); + +int pthread_setname_np(pthread_t, const char *) __nonnull(2); +#endif + #if defined(_POSIX_THREAD_PRIO_INHERIT) || defined(_POSIX_THREAD_PRIO_PROTECT) /* Mutex Initialization Scheduling Attributes, P1003.1c/Draft 10, p. 128 */ @@ -218,7 +231,7 @@ int _EXFUN(pthread_attr_setguardsize, * in GNU/Linux. They may be provided by other OSes for * compatibility. */ -#if defined(__GNU_VISIBLE) +#if __GNU_VISIBLE #if defined(__rtems__) int _EXFUN(pthread_attr_setaffinity_np, (pthread_attr_t *__attr, size_t __cpusetsize, @@ -235,7 +248,7 @@ int _EXFUN(pthread_getaffinity_np, int _EXFUN(pthread_getattr_np, (pthread_t __id, pthread_attr_t *__attr)); #endif /* defined(__rtems__) */ -#endif /* defined(__GNU_VISIBLE) */ +#endif /* __GNU_VISIBLE */ /* Thread Creation, P1003.1c/Draft 10, p. 144 */ @@ -253,7 +266,7 @@ int _EXFUN(pthread_detach, (pthread_t __pthread)); /* Thread Termination, p1003.1c/Draft 10, p. 150 */ -void _EXFUN(pthread_exit, (void *__value_ptr)); +void _EXFUN(pthread_exit, (void *__value_ptr)) __dead2; /* Get Calling Thread's ID, p1003.1c/Draft 10, p. XXX */ @@ -263,6 +276,18 @@ pthread_t _EXFUN(pthread_self, (void)); int _EXFUN(pthread_equal, (pthread_t __t1, pthread_t __t2)); +/* Retrieve ID of a Thread's CPU Time Clock */ +int _EXFUN(pthread_getcpuclockid, + (pthread_t thread, clockid_t *clock_id)); + +/* Get/Set Current Thread's Concurrency Level */ +int _EXFUN(pthread_setconcurrency, (int new_level)); +int _EXFUN(pthread_getconcurrency, (void)); + +#if __BSD_VISIBLE || __GNU_VISIBLE +void _EXFUN(pthread_yield, (void)); +#endif + /* Dynamic Package Initialization */ /* This is used to statically initialize a pthread_once_t. Example: @@ -271,7 +296,7 @@ int _EXFUN(pthread_equal, (pthread_t __t1, pthread_t __t2)); NOTE: This is named inconsistently -- it should be INITIALIZER. */ -#define PTHREAD_ONCE_INIT { 1, 0 } /* is initialized and not run */ +#define PTHREAD_ONCE_INIT _PTHREAD_ONCE_INIT int _EXFUN(pthread_once, (pthread_once_t *__once_control, void (*__init_routine)(void))); @@ -329,7 +354,7 @@ void _EXFUN(_pthread_cleanup_pop, _pthread_cleanup_pop(&_pthread_clup_ctx, (_execute)); \ } while (0) -#if defined(_GNU_SOURCE) +#if __GNU_VISIBLE void _EXFUN(_pthread_cleanup_push_defer, (struct _pthread_cleanup_context *_context, void (*_routine)(void *), void *_arg)); @@ -347,7 +372,7 @@ void _EXFUN(_pthread_cleanup_pop_restore, #define pthread_cleanup_pop_restore_np(_execute) \ _pthread_cleanup_pop_restore(&_pthread_clup_ctx, (_execute)); \ } while (0) -#endif /* defined(_GNU_SOURCE) */ +#endif /* __GNU_VISIBLE */ #if defined(_POSIX_THREAD_CPUTIME) @@ -398,7 +423,7 @@ int _EXFUN(pthread_spin_unlock, (pthread_spinlock_t *__spinlock)); pthread_mutex_t mutex = PTHREAD_RWLOCK_INITIALIZER; */ -#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) 0xFFFFFFFF) +#define PTHREAD_RWLOCK_INITIALIZER _PTHREAD_RWLOCK_INITIALIZER int _EXFUN(pthread_rwlockattr_init, (pthread_rwlockattr_t *__attr)); int _EXFUN(pthread_rwlockattr_destroy, (pthread_rwlockattr_t *__attr)); diff --git a/libc/xtensa-lx106-elf/include/pwd.h b/libc/xtensa-lx106-elf/include/pwd.h index 3dea4ee..f37d289 100644 --- a/libc/xtensa-lx106-elf/include/pwd.h +++ b/libc/xtensa-lx106-elf/include/pwd.h @@ -63,14 +63,14 @@ struct passwd { struct passwd *getpwuid (uid_t); struct passwd *getpwnam (const char *); -#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 500 +#if __MISC_VISIBLE || __POSIX_VISIBLE int getpwnam_r (const char *, struct passwd *, char *, size_t , struct passwd **); int getpwuid_r (uid_t, struct passwd *, char *, size_t, struct passwd **); #endif -#if __XSI_VISIBLE >= 500 +#if __MISC_VISIBLE || __XSI_VISIBLE >= 4 struct passwd *getpwent (void); void setpwent (void); void endpwent (void); diff --git a/libc/xtensa-lx106-elf/include/reent.h b/libc/xtensa-lx106-elf/include/reent.h index 861be71..b7664b0 100644 --- a/libc/xtensa-lx106-elf/include/reent.h +++ b/libc/xtensa-lx106-elf/include/reent.h @@ -92,7 +92,6 @@ extern "C" { #include #include -#include #define __need_size_t #define __need_ptrdiff_t diff --git a/libc/xtensa-lx106-elf/include/signal.h b/libc/xtensa-lx106-elf/include/signal.h index 8c50a2e..0324ae7 100644 --- a/libc/xtensa-lx106-elf/include/signal.h +++ b/libc/xtensa-lx106-elf/include/signal.h @@ -2,15 +2,18 @@ #define _SIGNAL_H_ #include "_ansi.h" +#include #include _BEGIN_STD_C typedef int sig_atomic_t; /* Atomic entity type (ANSI) */ -#ifndef _POSIX_SOURCE +#if __BSD_VISIBLE typedef _sig_func_ptr sig_t; /* BSD naming */ +#endif +#if __GNU_VISIBLE typedef _sig_func_ptr sighandler_t; /* glibc naming */ -#endif /* !_POSIX_SOURCE */ +#endif #define SIG_DFL ((_sig_func_ptr)0) /* Default action */ #define SIG_IGN ((_sig_func_ptr)1) /* Ignore action */ diff --git a/libc/xtensa-lx106-elf/include/stdint.h b/libc/xtensa-lx106-elf/include/stdint.h index 7386164..4abdacb 100644 --- a/libc/xtensa-lx106-elf/include/stdint.h +++ b/libc/xtensa-lx106-elf/include/stdint.h @@ -11,53 +11,30 @@ #include #include +#include #ifdef __cplusplus extern "C" { #endif -#ifdef ___int8_t_defined -typedef __int8_t int8_t ; -typedef __uint8_t uint8_t ; -#define __int8_t_defined 1 -#endif - #ifdef ___int_least8_t_defined typedef __int_least8_t int_least8_t; typedef __uint_least8_t uint_least8_t; #define __int_least8_t_defined 1 #endif -#ifdef ___int16_t_defined -typedef __int16_t int16_t ; -typedef __uint16_t uint16_t ; -#define __int16_t_defined 1 -#endif - #ifdef ___int_least16_t_defined typedef __int_least16_t int_least16_t; typedef __uint_least16_t uint_least16_t; #define __int_least16_t_defined 1 #endif -#ifdef ___int32_t_defined -typedef __int32_t int32_t ; -typedef __uint32_t uint32_t ; -#define __int32_t_defined 1 -#endif - #ifdef ___int_least32_t_defined typedef __int_least32_t int_least32_t; typedef __uint_least32_t uint_least32_t; #define __int_least32_t_defined 1 #endif -#ifdef ___int64_t_defined -typedef __int64_t int64_t ; -typedef __uint64_t uint64_t ; -#define __int64_t_defined 1 -#endif - #ifdef ___int_least64_t_defined typedef __int_least64_t int_least64_t; typedef __uint_least64_t uint_least64_t; @@ -147,37 +124,15 @@ typedef __uint_least64_t uint_least64_t; #endif #endif -/* Greatest-width integer types */ -/* Modern GCCs provide __INTMAX_TYPE__ */ -#if defined(__INTMAX_TYPE__) - typedef __INTMAX_TYPE__ intmax_t; -#elif __have_longlong64 - typedef signed long long intmax_t; -#else - typedef signed long intmax_t; -#endif - -/* Modern GCCs provide __UINTMAX_TYPE__ */ -#if defined(__UINTMAX_TYPE__) - typedef __UINTMAX_TYPE__ uintmax_t; -#elif __have_longlong64 - typedef unsigned long long uintmax_t; -#else - typedef unsigned long uintmax_t; -#endif - -typedef __intptr_t intptr_t; -typedef __uintptr_t uintptr_t; - #ifdef __INTPTR_TYPE__ #define INTPTR_MIN (-__INTPTR_MAX__ - 1) -#define INTPTR_MAX __INTPTR_MAX__ -#define UINTPTR_MAX __UINTPTR_MAX__ +#define INTPTR_MAX (__INTPTR_MAX__) +#define UINTPTR_MAX (__UINTPTR_MAX__) #elif defined(__PTRDIFF_TYPE__) #define INTPTR_MAX PTRDIFF_MAX #define INTPTR_MIN PTRDIFF_MIN #ifdef __UINTPTR_MAX__ -#define UINTPTR_MAX __UINTPTR_MAX__ +#define UINTPTR_MAX (__UINTPTR_MAX__) #else #define UINTPTR_MAX (2UL * PTRDIFF_MAX + 1) #endif @@ -186,7 +141,7 @@ typedef __uintptr_t uintptr_t; * Fallback to hardcoded values, * should be valid on cpu's with 32bit int/32bit void* */ -#define INTPTR_MAX __STDINT_EXP(LONG_MAX) +#define INTPTR_MAX (__STDINT_EXP(LONG_MAX)) #define INTPTR_MIN (-__STDINT_EXP(LONG_MAX) - 1) #define UINTPTR_MAX (__STDINT_EXP(LONG_MAX) * 2UL + 1) #endif @@ -195,77 +150,77 @@ typedef __uintptr_t uintptr_t; #ifdef __INT8_MAX__ #define INT8_MIN (-__INT8_MAX__ - 1) -#define INT8_MAX __INT8_MAX__ -#define UINT8_MAX __UINT8_MAX__ +#define INT8_MAX (__INT8_MAX__) +#define UINT8_MAX (__UINT8_MAX__) #elif defined(__int8_t_defined) -#define INT8_MIN -128 -#define INT8_MAX 127 -#define UINT8_MAX 255 +#define INT8_MIN (-128) +#define INT8_MAX (127) +#define UINT8_MAX (255) #endif #ifdef __INT_LEAST8_MAX__ #define INT_LEAST8_MIN (-__INT_LEAST8_MAX__ - 1) -#define INT_LEAST8_MAX __INT_LEAST8_MAX__ -#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__ +#define INT_LEAST8_MAX (__INT_LEAST8_MAX__) +#define UINT_LEAST8_MAX (__UINT_LEAST8_MAX__) #elif defined(__int_least8_t_defined) -#define INT_LEAST8_MIN -128 -#define INT_LEAST8_MAX 127 -#define UINT_LEAST8_MAX 255 +#define INT_LEAST8_MIN (-128) +#define INT_LEAST8_MAX (127) +#define UINT_LEAST8_MAX (255) #else #error required type int_least8_t missing #endif #ifdef __INT16_MAX__ #define INT16_MIN (-__INT16_MAX__ - 1) -#define INT16_MAX __INT16_MAX__ -#define UINT16_MAX __UINT16_MAX__ +#define INT16_MAX (__INT16_MAX__) +#define UINT16_MAX (__UINT16_MAX__) #elif defined(__int16_t_defined) -#define INT16_MIN -32768 -#define INT16_MAX 32767 -#define UINT16_MAX 65535 +#define INT16_MIN (-32768) +#define INT16_MAX (32767) +#define UINT16_MAX (65535) #endif #ifdef __INT_LEAST16_MAX__ #define INT_LEAST16_MIN (-__INT_LEAST16_MAX__ - 1) -#define INT_LEAST16_MAX __INT_LEAST16_MAX__ -#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__ +#define INT_LEAST16_MAX (__INT_LEAST16_MAX__) +#define UINT_LEAST16_MAX (__UINT_LEAST16_MAX__) #elif defined(__int_least16_t_defined) -#define INT_LEAST16_MIN -32768 -#define INT_LEAST16_MAX 32767 -#define UINT_LEAST16_MAX 65535 +#define INT_LEAST16_MIN (-32768) +#define INT_LEAST16_MAX (32767) +#define UINT_LEAST16_MAX (65535) #else #error required type int_least16_t missing #endif #ifdef __INT32_MAX__ #define INT32_MIN (-__INT32_MAX__ - 1) -#define INT32_MAX __INT32_MAX__ -#define UINT32_MAX __UINT32_MAX__ +#define INT32_MAX (__INT32_MAX__) +#define UINT32_MAX (__UINT32_MAX__) #elif defined(__int32_t_defined) -#if __have_long32 +#if defined (_INT32_EQ_LONG) #define INT32_MIN (-2147483647L-1) -#define INT32_MAX 2147483647L -#define UINT32_MAX 4294967295UL +#define INT32_MAX (2147483647L) +#define UINT32_MAX (4294967295UL) #else #define INT32_MIN (-2147483647-1) -#define INT32_MAX 2147483647 -#define UINT32_MAX 4294967295U +#define INT32_MAX (2147483647) +#define UINT32_MAX (4294967295U) #endif #endif #ifdef __INT_LEAST32_MAX__ #define INT_LEAST32_MIN (-__INT_LEAST32_MAX__ - 1) -#define INT_LEAST32_MAX __INT_LEAST32_MAX__ -#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__ +#define INT_LEAST32_MAX (__INT_LEAST32_MAX__) +#define UINT_LEAST32_MAX (__UINT_LEAST32_MAX__) #elif defined(__int_least32_t_defined) -#if __have_long32 +#if defined (_INT32_EQ_LONG) #define INT_LEAST32_MIN (-2147483647L-1) -#define INT_LEAST32_MAX 2147483647L -#define UINT_LEAST32_MAX 4294967295UL +#define INT_LEAST32_MAX (2147483647L) +#define UINT_LEAST32_MAX (4294967295UL) #else #define INT_LEAST32_MIN (-2147483647-1) -#define INT_LEAST32_MAX 2147483647 -#define UINT_LEAST32_MAX 4294967295U +#define INT_LEAST32_MAX (2147483647) +#define UINT_LEAST32_MAX (4294967295U) #endif #else #error required type int_least32_t missing @@ -273,44 +228,44 @@ typedef __uintptr_t uintptr_t; #ifdef __INT64_MAX__ #define INT64_MIN (-__INT64_MAX__ - 1) -#define INT64_MAX __INT64_MAX__ -#define UINT64_MAX __UINT64_MAX__ +#define INT64_MAX (__INT64_MAX__) +#define UINT64_MAX (__UINT64_MAX__) #elif defined(__int64_t_defined) #if __have_long64 #define INT64_MIN (-9223372036854775807L-1L) -#define INT64_MAX 9223372036854775807L -#define UINT64_MAX 18446744073709551615U +#define INT64_MAX (9223372036854775807L) +#define UINT64_MAX (18446744073709551615U) #elif __have_longlong64 #define INT64_MIN (-9223372036854775807LL-1LL) -#define INT64_MAX 9223372036854775807LL -#define UINT64_MAX 18446744073709551615ULL +#define INT64_MAX (9223372036854775807LL) +#define UINT64_MAX (18446744073709551615ULL) #endif #endif #ifdef __INT_LEAST64_MAX__ #define INT_LEAST64_MIN (-__INT_LEAST64_MAX__ - 1) -#define INT_LEAST64_MAX __INT_LEAST64_MAX__ -#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__ +#define INT_LEAST64_MAX (__INT_LEAST64_MAX__) +#define UINT_LEAST64_MAX (__UINT_LEAST64_MAX__) #elif defined(__int_least64_t_defined) #if __have_long64 #define INT_LEAST64_MIN (-9223372036854775807L-1L) -#define INT_LEAST64_MAX 9223372036854775807L -#define UINT_LEAST64_MAX 18446744073709551615U +#define INT_LEAST64_MAX (9223372036854775807L) +#define UINT_LEAST64_MAX (18446744073709551615U) #elif __have_longlong64 #define INT_LEAST64_MIN (-9223372036854775807LL-1LL) -#define INT_LEAST64_MAX 9223372036854775807LL -#define UINT_LEAST64_MAX 18446744073709551615ULL +#define INT_LEAST64_MAX (9223372036854775807LL) +#define UINT_LEAST64_MAX (18446744073709551615ULL) #endif #endif #ifdef __INT_FAST8_MAX__ #define INT_FAST8_MIN (-__INT_FAST8_MAX__ - 1) -#define INT_FAST8_MAX __INT_FAST8_MAX__ -#define UINT_FAST8_MAX __UINT_FAST8_MAX__ +#define INT_FAST8_MAX (__INT_FAST8_MAX__) +#define UINT_FAST8_MAX (__UINT_FAST8_MAX__) #elif defined(__int_fast8_t_defined) #if __STDINT_EXP(INT_MAX) >= 0x7f #define INT_FAST8_MIN (-__STDINT_EXP(INT_MAX)-1) -#define INT_FAST8_MAX __STDINT_EXP(INT_MAX) +#define INT_FAST8_MAX (__STDINT_EXP(INT_MAX)) #define UINT_FAST8_MAX (__STDINT_EXP(INT_MAX)*2U+1U) #else #define INT_FAST8_MIN INT_LEAST8_MIN @@ -321,12 +276,12 @@ typedef __uintptr_t uintptr_t; #ifdef __INT_FAST16_MAX__ #define INT_FAST16_MIN (-__INT_FAST16_MAX__ - 1) -#define INT_FAST16_MAX __INT_FAST16_MAX__ -#define UINT_FAST16_MAX __UINT_FAST16_MAX__ +#define INT_FAST16_MAX (__INT_FAST16_MAX__) +#define UINT_FAST16_MAX (__UINT_FAST16_MAX__) #elif defined(__int_fast16_t_defined) #if __STDINT_EXP(INT_MAX) >= 0x7fff #define INT_FAST16_MIN (-__STDINT_EXP(INT_MAX)-1) -#define INT_FAST16_MAX __STDINT_EXP(INT_MAX) +#define INT_FAST16_MAX (__STDINT_EXP(INT_MAX)) #define UINT_FAST16_MAX (__STDINT_EXP(INT_MAX)*2U+1U) #else #define INT_FAST16_MIN INT_LEAST16_MIN @@ -337,12 +292,12 @@ typedef __uintptr_t uintptr_t; #ifdef __INT_FAST32_MAX__ #define INT_FAST32_MIN (-__INT_FAST32_MAX__ - 1) -#define INT_FAST32_MAX __INT_FAST32_MAX__ -#define UINT_FAST32_MAX __UINT_FAST32_MAX__ +#define INT_FAST32_MAX (__INT_FAST32_MAX__) +#define UINT_FAST32_MAX (__UINT_FAST32_MAX__) #elif defined(__int_fast32_t_defined) #if __STDINT_EXP(INT_MAX) >= 0x7fffffff #define INT_FAST32_MIN (-__STDINT_EXP(INT_MAX)-1) -#define INT_FAST32_MAX __STDINT_EXP(INT_MAX) +#define INT_FAST32_MAX (__STDINT_EXP(INT_MAX)) #define UINT_FAST32_MAX (__STDINT_EXP(INT_MAX)*2U+1U) #else #define INT_FAST32_MIN INT_LEAST32_MIN @@ -353,12 +308,12 @@ typedef __uintptr_t uintptr_t; #ifdef __INT_FAST64_MAX__ #define INT_FAST64_MIN (-__INT_FAST64_MAX__ - 1) -#define INT_FAST64_MAX __INT_FAST64_MAX__ -#define UINT_FAST64_MAX __UINT_FAST64_MAX__ +#define INT_FAST64_MAX (__INT_FAST64_MAX__) +#define UINT_FAST64_MAX (__UINT_FAST64_MAX__) #elif defined(__int_fast64_t_defined) #if __STDINT_EXP(INT_MAX) > 0x7fffffff #define INT_FAST64_MIN (-__STDINT_EXP(INT_MAX)-1) -#define INT_FAST64_MAX __STDINT_EXP(INT_MAX) +#define INT_FAST64_MAX (__STDINT_EXP(INT_MAX)) #define UINT_FAST64_MAX (__STDINT_EXP(INT_MAX)*2U+1U) #else #define INT_FAST64_MIN INT_LEAST64_MIN @@ -368,7 +323,7 @@ typedef __uintptr_t uintptr_t; #endif #ifdef __INTMAX_MAX__ -#define INTMAX_MAX __INTMAX_MAX__ +#define INTMAX_MAX (__INTMAX_MAX__) #define INTMAX_MIN (-INTMAX_MAX - 1) #elif defined(__INTMAX_TYPE__) /* All relevant GCC versions prefer long to long long for intmax_t. */ @@ -377,7 +332,7 @@ typedef __uintptr_t uintptr_t; #endif #ifdef __UINTMAX_MAX__ -#define UINTMAX_MAX __UINTMAX_MAX__ +#define UINTMAX_MAX (__UINTMAX_MAX__) #elif defined(__UINTMAX_TYPE__) /* All relevant GCC versions prefer long to long long for intmax_t. */ #define UINTMAX_MAX UINT64_MAX @@ -385,27 +340,27 @@ typedef __uintptr_t uintptr_t; /* This must match size_t in stddef.h, currently long unsigned int */ #ifdef __SIZE_MAX__ -#define SIZE_MAX __SIZE_MAX__ +#define SIZE_MAX (__SIZE_MAX__) #else #define SIZE_MAX (__STDINT_EXP(LONG_MAX) * 2UL + 1) #endif /* This must match sig_atomic_t in (currently int) */ #define SIG_ATOMIC_MIN (-__STDINT_EXP(INT_MAX) - 1) -#define SIG_ATOMIC_MAX __STDINT_EXP(INT_MAX) +#define SIG_ATOMIC_MAX (__STDINT_EXP(INT_MAX)) /* This must match ptrdiff_t in (currently long int) */ #ifdef __PTRDIFF_MAX__ -#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define PTRDIFF_MAX (__PTRDIFF_MAX__) #else -#define PTRDIFF_MAX __STDINT_EXP(LONG_MAX) +#define PTRDIFF_MAX (__STDINT_EXP(LONG_MAX)) #endif #define PTRDIFF_MIN (-PTRDIFF_MAX - 1) /* This must match definition in */ #ifndef WCHAR_MIN #ifdef __WCHAR_MIN__ -#define WCHAR_MIN __WCHAR_MIN__ +#define WCHAR_MIN (__WCHAR_MIN__) #elif defined(__WCHAR_UNSIGNED__) || (L'\0' - 1 > 0) #define WCHAR_MIN (0 + L'\0') #else @@ -416,7 +371,7 @@ typedef __uintptr_t uintptr_t; /* This must match definition in */ #ifndef WCHAR_MAX #ifdef __WCHAR_MAX__ -#define WCHAR_MAX __WCHAR_MAX__ +#define WCHAR_MAX (__WCHAR_MAX__) #elif defined(__WCHAR_UNSIGNED__) || (L'\0' - 1 > 0) #define WCHAR_MAX (0xffffffffu + L'\0') #else @@ -426,14 +381,14 @@ typedef __uintptr_t uintptr_t; /* wint_t is unsigned int on almost all GCC targets. */ #ifdef __WINT_MAX__ -#define WINT_MAX __WINT_MAX__ +#define WINT_MAX (__WINT_MAX__) #else #define WINT_MAX (__STDINT_EXP(INT_MAX) * 2U + 1U) #endif #ifdef __WINT_MIN__ -#define WINT_MIN __WINT_MIN__ +#define WINT_MIN (__WINT_MIN__) #else -#define WINT_MIN 0U +#define WINT_MIN (0U) #endif /** Macros for minimum-width integer constant expressions */ @@ -465,7 +420,7 @@ typedef __uintptr_t uintptr_t; #define INT32_C(x) __INT32_C(x) #define UINT32_C(x) __UINT32_C(x) #else -#if __have_long32 +#if defined (_INT32_EQ_LONG) #define INT32_C(x) x##L #define UINT32_C(x) x##UL #else diff --git a/libc/xtensa-lx106-elf/include/stdio.h b/libc/xtensa-lx106-elf/include/stdio.h index e336ee6..ee0f612 100644 --- a/libc/xtensa-lx106-elf/include/stdio.h +++ b/libc/xtensa-lx106-elf/include/stdio.h @@ -35,9 +35,22 @@ #include #include +/* typedef only __gnuc_va_list, used throughout the header */ #define __need___va_list #include +/* typedef va_list only when required */ +#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE +#ifdef __GNUC__ +#ifndef _VA_LIST_DEFINED +typedef __gnuc_va_list va_list; +#define _VA_LIST_DEFINED +#endif +#else /* !__GNUC__ */ +#include +#endif +#endif /* __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE */ + /* * defines __FILE, _fpos_t. * They must be defined there because struct _reent needs them (and we don't @@ -49,7 +62,10 @@ _BEGIN_STD_C +#if !defined(__FILE_defined) typedef __FILE FILE; +# define __FILE_defined +#endif #ifdef __CYGWIN__ typedef _fpos64_t fpos_t; @@ -125,7 +141,7 @@ typedef _fpos64_t fpos64_t; #define L_tmpnam FILENAME_MAX #endif -#ifndef __STRICT_ANSI__ +#if __BSD_VISIBLE || __XSI_VISIBLE #define P_tmpdir "/tmp" #endif @@ -161,6 +177,12 @@ typedef _fpos64_t fpos64_t; #endif #endif +#if __POSIX_VISIBLE +char * _EXFUN(ctermid, (char *)); +#endif +#if __XSI_VISIBLE && __XSI_VISIBLE < 600 +char * _EXFUN(cuserid, (char *)); +#endif FILE * _EXFUN(tmpfile, (void)); char * _EXFUN(tmpnam, (char *)); #if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 @@ -227,7 +249,7 @@ int _EXFUN(rename, (const char *, const char *)); int _EXFUN(_rename, (const char *, const char *)); #endif #endif -#if !defined(__STRICT_ANSI__) || defined(__USE_XOPEN2K) +#if __LARGEFILE_VISIBLE || __POSIX_VISIBLE >= 200112 #ifdef _COMPILING_NEWLIB int _EXFUN(fseeko, (FILE *, _off_t, int)); _off_t _EXFUN(ftello, ( FILE *)); @@ -239,16 +261,32 @@ off_t _EXFUN(ftello, ( FILE *)); #if __GNU_VISIBLE int _EXFUN(fcloseall, (_VOID)); #endif -#if !defined(__STRICT_ANSI__) || (__STDC_VERSION__ >= 199901L) || (__cplusplus >= 201103L) #ifndef _REENT_ONLY +#if __ISO_C_VISIBLE >= 1999 +int _EXFUN(snprintf, (char *__restrict, size_t, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); +int _EXFUN(vsnprintf, (char *__restrict, size_t, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); +int _EXFUN(vfscanf, (FILE *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +int _EXFUN(vscanf, (const char *, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 1, 0)))); +int _EXFUN(vsscanf, (const char *__restrict, const char *__restrict, __VALIST) + _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +#endif +#if __GNU_VISIBLE +int _EXFUN(asprintf, (char **__restrict, const char *__restrict, ...) + _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); +int _EXFUN(vasprintf, (char **, const char *, __VALIST) + _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); +#endif +#if __MISC_VISIBLE /* Newlib-specific */ int _EXFUN(asiprintf, (char **, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); char * _EXFUN(asniprintf, (char *, size_t *, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); char * _EXFUN(asnprintf, (char *__restrict, size_t *__restrict, const char *__restrict, ...) _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); -int _EXFUN(asprintf, (char **__restrict, const char *__restrict, ...) - _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); #ifndef diprintf int _EXFUN(diprintf, (int, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); @@ -265,8 +303,6 @@ int _EXFUN(siprintf, (char *, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 2, 3)))); int _EXFUN(siscanf, (const char *, const char *, ...) _ATTRIBUTE ((__format__ (__scanf__, 2, 3)))); -int _EXFUN(snprintf, (char *__restrict, size_t, const char *__restrict, ...) - _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); int _EXFUN(sniprintf, (char *, size_t, const char *, ...) _ATTRIBUTE ((__format__ (__printf__, 3, 4)))); int _EXFUN(vasiprintf, (char **, const char *, __VALIST) @@ -275,50 +311,50 @@ char * _EXFUN(vasniprintf, (char *, size_t *, const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); char * _EXFUN(vasnprintf, (char *, size_t *, const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); -int _EXFUN(vasprintf, (char **, const char *, __VALIST) - _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); int _EXFUN(vdiprintf, (int, const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); int _EXFUN(vfiprintf, (FILE *, const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); int _EXFUN(vfiscanf, (FILE *, const char *, __VALIST) _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); -int _EXFUN(vfscanf, (FILE *__restrict, const char *__restrict, __VALIST) - _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); int _EXFUN(viprintf, (const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 1, 0)))); int _EXFUN(viscanf, (const char *, __VALIST) _ATTRIBUTE ((__format__ (__scanf__, 1, 0)))); -int _EXFUN(vscanf, (const char *, __VALIST) - _ATTRIBUTE ((__format__ (__scanf__, 1, 0)))); int _EXFUN(vsiprintf, (char *, const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); int _EXFUN(vsiscanf, (const char *, const char *, __VALIST) _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); int _EXFUN(vsniprintf, (char *, size_t, const char *, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); -int _EXFUN(vsnprintf, (char *__restrict, size_t, const char *__restrict, __VALIST) - _ATTRIBUTE ((__format__ (__printf__, 3, 0)))); -int _EXFUN(vsscanf, (const char *__restrict, const char *__restrict, __VALIST) - _ATTRIBUTE ((__format__ (__scanf__, 2, 0)))); +#endif /* __MISC_VISIBLE */ #endif /* !_REENT_ONLY */ -#endif /* !__STRICT_ANSI__ */ /* * Routines in POSIX 1003.1:2001. */ -#ifndef __STRICT_ANSI__ +#if __POSIX_VISIBLE #ifndef _REENT_ONLY FILE * _EXFUN(fdopen, (int, const char *)); #endif int _EXFUN(fileno, (FILE *)); -int _EXFUN(getw, (FILE *)); +#endif +#if __MISC_VISIBLE || __POSIX_VISIBLE >= 199209 int _EXFUN(pclose, (FILE *)); FILE * _EXFUN(popen, (const char *, const char *)); -int _EXFUN(putw, (int, FILE *)); +#endif + +#if __BSD_VISIBLE void _EXFUN(setbuffer, (FILE *, char *, int)); int _EXFUN(setlinebuf, (FILE *)); +#endif + +#if __MISC_VISIBLE || (__XSI_VISIBLE && __POSIX_VISIBLE < 200112) +int _EXFUN(getw, (FILE *)); +int _EXFUN(putw, (int, FILE *)); +#endif +#if __MISC_VISIBLE || __POSIX_VISIBLE int _EXFUN(getc_unlocked, (FILE *)); int _EXFUN(getchar_unlocked, (void)); void _EXFUN(flockfile, (FILE *)); @@ -326,13 +362,13 @@ int _EXFUN(ftrylockfile, (FILE *)); void _EXFUN(funlockfile, (FILE *)); int _EXFUN(putc_unlocked, (int, FILE *)); int _EXFUN(putchar_unlocked, (int)); -#endif /* ! __STRICT_ANSI__ */ +#endif /* * Routines in POSIX 1003.1:200x. */ -#ifndef __STRICT_ANSI__ +#if __POSIX_VISIBLE >= 200809 # ifndef _REENT_ONLY # ifndef dprintf int _EXFUN(dprintf, (int, const char *__restrict, ...) @@ -342,13 +378,16 @@ FILE * _EXFUN(fmemopen, (void *__restrict, size_t, const char *__restrict)); /* getdelim - see __getdelim for now */ /* getline - see __getline for now */ FILE * _EXFUN(open_memstream, (char **, size_t *)); -#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 -int _EXFUN(renameat, (int, const char *, int, const char *)); -#endif int _EXFUN(vdprintf, (int, const char *__restrict, __VALIST) _ATTRIBUTE ((__format__ (__printf__, 2, 0)))); # endif #endif +#if __ATFILE_VISIBLE +int _EXFUN(renameat, (int, const char *, int, const char *)); +# ifdef __CYGWIN__ +int _EXFUN(renameat2, (int, const char *, int, const char *, unsigned int)); +# endif +#endif /* * Recursive versions of the above. @@ -492,7 +531,7 @@ int _EXFUN(fpurge, (FILE *)); ssize_t _EXFUN(__getdelim, (char **, size_t *, int, FILE *)); ssize_t _EXFUN(__getline, (char **, size_t *, FILE *)); -#if __BSD_VISIBLE +#if __MISC_VISIBLE void _EXFUN(clearerr_unlocked, (FILE *)); int _EXFUN(feof_unlocked, (FILE *)); int _EXFUN(ferror_unlocked, (FILE *)); @@ -542,7 +581,7 @@ int _EXFUN(__swbuf_r, (struct _reent *, int, FILE *)); * Stdio function-access interface. */ -#ifndef __STRICT_ANSI__ +#if __BSD_VISIBLE # ifdef __LARGE64_FILES FILE *_EXFUN(funopen,(const _PTR __cookie, int (*__readfn)(_PTR __c, char *__buf, @@ -579,7 +618,9 @@ FILE *_EXFUN(_funopen_r,(struct _reent *, const _PTR __cookie, (fpos_t (*)())0, (int (*)())0) # define fwopen(__cookie, __fn) funopen(__cookie, (int (*)())0, __fn, \ (fpos_t (*)())0, (int (*)())0) +#endif /* __BSD_VISIBLE */ +#if __GNU_VISIBLE typedef ssize_t cookie_read_function_t(void *__cookie, char *__buf, size_t __n); typedef ssize_t cookie_write_function_t(void *__cookie, const char *__buf, size_t __n); @@ -603,7 +644,7 @@ FILE *_EXFUN(fopencookie,(void *__cookie, const char *__mode, cookie_io_functions_t __functions)); FILE *_EXFUN(_fopencookie_r,(struct _reent *, void *__cookie, const char *__mode, cookie_io_functions_t __functions)); -#endif /* ! __STRICT_ANSI__ */ +#endif /* __GNU_VISIBLE */ #ifndef __CUSTOM_FILE_IO__ /* @@ -642,10 +683,12 @@ _ELIDABLE_INLINE int __sgetc_r(struct _reent *__ptr, FILE *__p) #define __sgetc_r(__ptr, __p) __sgetc_raw_r(__ptr, __p) #endif -#ifdef _never /* __GNUC__ */ -/* If this inline is actually used, then systems using coff debugging - info get hopelessly confused. 21sept93 rich@cygnus.com. */ +#ifdef __GNUC__ _ELIDABLE_INLINE int __sputc_r(struct _reent *_ptr, int _c, FILE *_p) { +#ifdef __SCLE + if ((_p->_flags & __SCLE) && _c == '\n') + __sputc_r (_ptr, '\r', _p); +#endif if (--_p->_w >= 0 || (_p->_w >= _p->_lbfsize && (char)_c != '\n')) return (*_p->_p++ = _c); else @@ -678,50 +721,79 @@ _ELIDABLE_INLINE int __sputc_r(struct _reent *_ptr, int _c, FILE *_p) { #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF))) #define __sfileno(p) ((p)->_file) +#ifndef __cplusplus #ifndef _REENT_SMALL #define feof(p) __sfeof(p) #define ferror(p) __sferror(p) #define clearerr(p) __sclearerr(p) -#if __BSD_VISIBLE +#if __MISC_VISIBLE #define feof_unlocked(p) __sfeof(p) #define ferror_unlocked(p) __sferror(p) #define clearerr_unlocked(p) __sclearerr(p) -#endif /* __BSD_VISIBLE */ +#endif /* __MISC_VISIBLE */ #endif /* _REENT_SMALL */ -#if 0 /*ndef __STRICT_ANSI__ - FIXME: must initialize stdio first, use fn */ +#if 0 /* __POSIX_VISIBLE - FIXME: must initialize stdio first, use fn */ #define fileno(p) __sfileno(p) #endif -#ifndef __CYGWIN__ -#ifndef lint -#define getc(fp) __sgetc_r(_REENT, fp) -#define putc(x, fp) __sputc_r(_REENT, x, fp) -#endif /* lint */ -#endif /* __CYGWIN__ */ +static __inline int +_getchar_unlocked(void) +{ + struct _reent *_ptr; -#ifndef __STRICT_ANSI__ + _ptr = _REENT; + return (__sgetc_r(_ptr, _stdin_r(_ptr))); +} + +static __inline int +_putchar_unlocked(int _c) +{ + struct _reent *_ptr; + + _ptr = _REENT; + return (__sputc_r(_ptr, _c, _stdout_r(_ptr))); +} + +#ifdef __SINGLE_THREAD__ +#define getc(_p) __sgetc_r(_REENT, _p) +#define putc(_c, _p) __sputc_r(_REENT, _c, _p) +#define getchar() _getchar_unlocked() +#define putchar(_c) _putchar_unlocked(_c) +#endif /* __SINGLE_THREAD__ */ + +#if __MISC_VISIBLE || __POSIX_VISIBLE +#define getchar_unlocked() _getchar_unlocked() +#define putchar_unlocked(_c) _putchar_unlocked(_c) +#endif +#endif /* __cplusplus */ + +#if __MISC_VISIBLE /* fast always-buffered version, true iff error */ #define fast_putc(x,p) (--(p)->_w < 0 ? \ __swbuf_r(_REENT, (int)(x), p) == EOF : (*(p)->_p = (x), (p)->_p++, 0)) +#endif +#if __GNU_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 600) #define L_cuserid 9 /* posix says it goes in stdio.h :( */ -#ifdef __CYGWIN__ +#endif +#if __POSIX_VISIBLE #define L_ctermid 16 #endif -#endif -#endif /* !__CUSTOM_FILE_IO__ */ +#else /* __CUSTOM_FILE_IO__ */ #define getchar() getc(stdin) #define putchar(x) putc(x, stdout) -#ifndef __STRICT_ANSI__ +#if __MISC_VISIBLE || __POSIX_VISIBLE #define getchar_unlocked() getc_unlocked(stdin) #define putchar_unlocked(x) putc_unlocked(x, stdout) #endif +#endif /* !__CUSTOM_FILE_IO__ */ + _END_STD_C #endif /* _STDIO_H_ */ diff --git a/libc/xtensa-lx106-elf/include/stdlib.h b/libc/xtensa-lx106-elf/include/stdlib.h index 254ddd7..c4e6633 100644 --- a/libc/xtensa-lx106-elf/include/stdlib.h +++ b/libc/xtensa-lx106-elf/include/stdlib.h @@ -26,6 +26,10 @@ #include #endif +#if __GNU_VISIBLE +#include +#endif + _BEGIN_STD_C typedef struct @@ -40,9 +44,7 @@ typedef struct long rem; /* remainder */ } ldiv_t; -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +#if __ISO_C_VISIBLE >= 1999 typedef struct { long long int quot; /* quotient */ @@ -70,9 +72,14 @@ int _EXFUN(__locale_mb_cur_max,(_VOID)); _VOID _EXFUN(abort,(_VOID) _ATTRIBUTE ((__noreturn__))); int _EXFUN(abs,(int)); +#if __BSD_VISIBLE +__uint32_t _EXFUN(arc4random, (void)); +__uint32_t _EXFUN(arc4random_uniform, (__uint32_t)); +void _EXFUN(arc4random_buf, (void *, size_t)); +#endif int _EXFUN(atexit,(_VOID (*__func)(_VOID))); double _EXFUN(atof,(const char *__nptr)); -#ifndef __STRICT_ANSI__ +#if __MISC_VISIBLE float _EXFUN(atoff,(const char *__nptr)); #endif int _EXFUN(atoi,(const char *__nptr)); @@ -92,7 +99,7 @@ char * _EXFUN(getenv,(const char *__string)); char * _EXFUN(_getenv_r,(struct _reent *, const char *__string)); char * _EXFUN(_findenv,(_CONST char *, int *)); char * _EXFUN(_findenv_r,(struct _reent *, _CONST char *, int *)); -#ifndef __STRICT_ANSI__ +#if __POSIX_VISIBLE >= 200809 extern char *suboptarg; /* getsubopt(3) external variable */ int _EXFUN(getsubopt,(char **, char * const *, char **)); #endif @@ -109,48 +116,64 @@ size_t _EXFUN(mbstowcs,(wchar_t *__restrict, const char *__restrict, size_t)); size_t _EXFUN(_mbstowcs_r,(struct _reent *, wchar_t *__restrict, const char *__restrict, size_t, _mbstate_t *)); size_t _EXFUN(wcstombs,(char *__restrict, const wchar_t *__restrict, size_t)); size_t _EXFUN(_wcstombs_r,(struct _reent *, char *__restrict, const wchar_t *__restrict, size_t, _mbstate_t *)); -#ifndef __STRICT_ANSI__ #ifndef _REENT_ONLY +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 char * _EXFUN(mkdtemp,(char *)); +#endif +#if __GNU_VISIBLE int _EXFUN(mkostemp,(char *, int)); int _EXFUN(mkostemps,(char *, int, int)); +#endif +#if __MISC_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 4 int _EXFUN(mkstemp,(char *)); +#endif +#if __MISC_VISIBLE int _EXFUN(mkstemps,(char *, int)); +#endif #if (__GNUC__ < 4) || defined(__XTENSA__) char * _EXFUN(mktemp,(char *)); #else -char * _EXFUN(mktemp,(char *) _ATTRIBUTE ((__warning__ ("the use of `mktemp' is dangerous; use `mkstemp' instead")))); +#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112) +char * _EXFUN(mktemp,(char *) _ATTRIBUTE ((__deprecated__("the use of `mktemp' is dangerous; use `mkstemp' instead")))); #endif #endif +#endif /* !_REENT_ONLY */ char * _EXFUN(_mkdtemp_r, (struct _reent *, char *)); int _EXFUN(_mkostemp_r, (struct _reent *, char *, int)); int _EXFUN(_mkostemps_r, (struct _reent *, char *, int, int)); int _EXFUN(_mkstemp_r, (struct _reent *, char *)); int _EXFUN(_mkstemps_r, (struct _reent *, char *, int)); #if (__GNUC__ < 4) || defined(__XTENSA__) -char * _EXFUN(_mktemp_r, (struct _reent *, char *)); +char * _EXFUN(_mktemp_r, (struct _reent *, char *)); #else -char * _EXFUN(_mktemp_r, (struct _reent *, char *) _ATTRIBUTE ((__warning__ ("the use of `mktemp' is dangerous; use `mkstemp' instead")))); -#endif +char * _EXFUN(_mktemp_r, (struct _reent *, char *) _ATTRIBUTE ((__deprecated__("the use of `mktemp' is dangerous; use `mkstemp' instead")))); #endif _VOID _EXFUN(qsort,(_PTR __base, size_t __nmemb, size_t __size, __compar_fn_t _compar)); int _EXFUN(rand,(_VOID)); _PTR _EXFUN_NOTHROW(realloc,(_PTR __r, size_t __size)); -#ifndef __STRICT_ANSI__ +#if __BSD_VISIBLE +void *reallocarray(void *, size_t, size_t) __result_use_check __alloc_size(2) + __alloc_size(3); _PTR _EXFUN(reallocf,(_PTR __r, size_t __size)); +#endif +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 char * _EXFUN(realpath, (const char *__restrict path, char *__restrict resolved_path)); #endif +#if __BSD_VISIBLE +int _EXFUN(rpmatch, (const char *response)); +#endif +#if __XSI_VISIBLE +_VOID _EXFUN(setkey, (const char *__key)); +#endif _VOID _EXFUN(srand,(unsigned __seed)); double _EXFUN(strtod,(const char *__restrict __n, char **__restrict __end_PTR)); double _EXFUN(_strtod_r,(struct _reent *,const char *__restrict __n, char **__restrict __end_PTR)); -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +#if __ISO_C_VISIBLE >= 1999 float _EXFUN(strtof,(const char *__restrict __n, char **__restrict __end_PTR)); #endif -#ifndef __STRICT_ANSI__ +#if __MISC_VISIBLE /* the following strtodf interface is deprecated...use strtof instead */ -# ifndef strtodf +# ifndef strtodf # define strtodf strtof # endif #endif @@ -159,26 +182,45 @@ long _EXFUN(_strtol_r,(struct _reent *,const char *__restrict __n, char **__rest unsigned long _EXFUN(strtoul,(const char *__restrict __n, char **__restrict __end_PTR, int __base)); unsigned long _EXFUN(_strtoul_r,(struct _reent *,const char *__restrict __n, char **__restrict __end_PTR, int __base)); +#if __GNU_VISIBLE +double strtod_l (const char *__restrict, char **__restrict, locale_t); +float strtof_l (const char *__restrict, char **__restrict, locale_t); +#ifdef _HAVE_LONG_DOUBLE +extern long double strtold_l (const char *__restrict, char **__restrict, + locale_t); +#endif /* _HAVE_LONG_DOUBLE */ +long strtol_l (const char *__restrict, char **__restrict, int, locale_t); +unsigned long strtoul_l (const char *__restrict, char **__restrict, int, + locale_t __loc); +long long strtoll_l (const char *__restrict, char **__restrict, int, locale_t); +unsigned long long strtoull_l (const char *__restrict, char **__restrict, int, + locale_t __loc); +#endif + int _EXFUN(system,(const char *__string)); -#ifndef __STRICT_ANSI__ +#if __SVID_VISIBLE || __XSI_VISIBLE >= 4 long _EXFUN(a64l,(const char *__input)); char * _EXFUN(l64a,(long __input)); char * _EXFUN(_l64a_r,(struct _reent *,long __input)); +#endif +#if __MISC_VISIBLE int _EXFUN(on_exit,(_VOID (*__func)(int, _PTR),_PTR __arg)); -#endif /* ! __STRICT_ANSI__ */ -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +#endif +#if __ISO_C_VISIBLE >= 1999 _VOID _EXFUN(_Exit,(int __status) _ATTRIBUTE ((__noreturn__))); #endif -#ifndef __STRICT_ANSI__ +#if __SVID_VISIBLE || __XSI_VISIBLE int _EXFUN(putenv,(char *__string)); +#endif int _EXFUN(_putenv_r,(struct _reent *, char *__string)); _PTR _EXFUN(_reallocf_r,(struct _reent *, _PTR, size_t)); +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 int _EXFUN(setenv,(const char *__string, const char *__value, int __overwrite)); +#endif int _EXFUN(_setenv_r,(struct _reent *, const char *__string, const char *__value, int __overwrite)); +#if __XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112 char * _EXFUN(gcvt,(double,int,char *)); char * _EXFUN(gcvtf,(float,int,char *)); char * _EXFUN(fcvt,(double,int,int *,int *)); @@ -187,15 +229,18 @@ char * _EXFUN(ecvt,(double,int,int *,int *)); char * _EXFUN(ecvtbuf,(double, int, int*, int*, char *)); char * _EXFUN(fcvtbuf,(double, int, int*, int*, char *)); char * _EXFUN(ecvtf,(float,int,int *,int *)); -char * _EXFUN(dtoa,(double, int, int, int *, int*, char**)); #endif char * _EXFUN(__itoa,(int, char *, int)); char * _EXFUN(__utoa,(unsigned, char *, int)); -#ifndef __STRICT_ANSI__ +#if __MISC_VISIBLE char * _EXFUN(itoa,(int, char *, int)); char * _EXFUN(utoa,(unsigned, char *, int)); +#endif +#if __POSIX_VISIBLE int _EXFUN(rand_r,(unsigned *__seed)); +#endif +#if __SVID_VISIBLE || __XSI_VISIBLE double _EXFUN(drand48,(_VOID)); double _EXFUN(_drand48_r,(struct _reent *)); double _EXFUN(erand48,(unsigned short [3])); @@ -216,45 +261,42 @@ unsigned short * _EXFUN(_seed48_r,(struct _reent *, unsigned short [3])); _VOID _EXFUN(srand48,(long)); _VOID _EXFUN(_srand48_r,(struct _reent *, long)); -#endif /* ! __STRICT_ANSI__ */ -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +#endif /* __SVID_VISIBLE || __XSI_VISIBLE */ +#if __SVID_VISIBLE || __XSI_VISIBLE >= 4 || __BSD_VISIBLE +char * _EXFUN(initstate,(unsigned, char *, size_t)); +long _EXFUN(random,(_VOID)); +char * _EXFUN(setstate,(char *)); +_VOID _EXFUN(srandom,(unsigned)); +#endif +#if __ISO_C_VISIBLE >= 1999 long long _EXFUN(atoll,(const char *__nptr)); #endif -#ifndef __STRICT_ANSI__ long long _EXFUN(_atoll_r,(struct _reent *, const char *__nptr)); -#endif /* ! __STRICT_ANSI__ */ -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +#if __ISO_C_VISIBLE >= 1999 long long _EXFUN(llabs,(long long)); lldiv_t _EXFUN(lldiv,(long long __numer, long long __denom)); long long _EXFUN(strtoll,(const char *__restrict __n, char **__restrict __end_PTR, int __base)); #endif -#ifndef __STRICT_ANSI__ long long _EXFUN(_strtoll_r,(struct _reent *, const char *__restrict __n, char **__restrict __end_PTR, int __base)); -#endif /* ! __STRICT_ANSI__ */ -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +#if __ISO_C_VISIBLE >= 1999 unsigned long long _EXFUN(strtoull,(const char *__restrict __n, char **__restrict __end_PTR, int __base)); #endif -#ifndef __STRICT_ANSI__ unsigned long long _EXFUN(_strtoull_r,(struct _reent *, const char *__restrict __n, char **__restrict __end_PTR, int __base)); #ifndef __CYGWIN__ +#if __MISC_VISIBLE _VOID _EXFUN(cfree,(_PTR)); +#endif +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 int _EXFUN(unsetenv,(const char *__string)); +#endif int _EXFUN(_unsetenv_r,(struct _reent *, const char *__string)); -#endif +#endif /* !__CYGWIN__ */ -#ifdef __rtems__ -int _EXFUN(posix_memalign,(void **, size_t, size_t)); +#if __POSIX_VISIBLE >= 200112 +int _EXFUN(__nonnull (1) posix_memalign,(void **, size_t, size_t)); #endif -#endif /* ! __STRICT_ANSI__ */ - char * _EXFUN(_dtoa_r,(struct _reent *, double, int, int, int *, int*, char**)); #ifndef __CYGWIN__ _PTR _EXFUN_NOTHROW(_malloc_r,(struct _reent *, size_t)); @@ -271,7 +313,9 @@ _VOID _EXFUN(__eprintf,(const char *, const char *, unsigned int, const char *)) _BSD_SOURCE, you get the BSD version; otherwise you get the GNU version. We want that #undef qsort_r will still let you invoke the underlying function, but that requires gcc support. */ -#ifdef _BSD_SOURCE +#if __GNU_VISIBLE +_VOID _EXFUN(qsort_r,(_PTR __base, size_t __nmemb, size_t __size, int (*_compar)(const _PTR, const _PTR, _PTR), _PTR __thunk)); +#elif __BSD_VISIBLE # ifdef __GNUC__ _VOID _EXFUN(qsort_r,(_PTR __base, size_t __nmemb, size_t __size, _PTR __thunk, int (*_compar)(_PTR, const _PTR, const _PTR))) __asm__ (__ASMNAME ("__bsd_qsort_r")); @@ -279,19 +323,27 @@ _VOID _EXFUN(qsort_r,(_PTR __base, size_t __nmemb, size_t __size, _PTR __thunk, _VOID _EXFUN(__bsd_qsort_r,(_PTR __base, size_t __nmemb, size_t __size, _PTR __thunk, int (*_compar)(_PTR, const _PTR, const _PTR))); # define qsort_r __bsd_qsort_r # endif -#elif __GNU_VISIBLE -_VOID _EXFUN(qsort_r,(_PTR __base, size_t __nmemb, size_t __size, int (*_compar)(const _PTR, const _PTR, _PTR), _PTR __thunk)); #endif /* On platforms where long double equals double. */ #ifdef _HAVE_LONG_DOUBLE -#if !defined(__STRICT_ANSI__) || \ - (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ - (defined(__cplusplus) && __cplusplus >= 201103L) +extern long double _strtold_r (struct _reent *, const char *__restrict, char **__restrict); +#if __ISO_C_VISIBLE >= 1999 extern long double strtold (const char *__restrict, char **__restrict); #endif #endif /* _HAVE_LONG_DOUBLE */ +/* + * If we're in a mode greater than C99, expose C11 functions. + */ +#if __ISO_C_VISIBLE >= 2011 +void * aligned_alloc(size_t, size_t) __malloc_like __alloc_align(1) + __alloc_size(2); +int at_quick_exit(void (*)(void)); +_Noreturn void + quick_exit(int); +#endif /* __ISO_C_VISIBLE >= 2011 */ + _END_STD_C #endif /* _STDLIB_H_ */ diff --git a/libc/xtensa-lx106-elf/include/string.h b/libc/xtensa-lx106-elf/include/string.h index af5c9da..9c536f3 100644 --- a/libc/xtensa-lx106-elf/include/string.h +++ b/libc/xtensa-lx106-elf/include/string.h @@ -16,6 +16,14 @@ #define __need_NULL #include +#if __POSIX_VISIBLE >= 200809 +#include +#endif + +#if __BSD_VISIBLE +#include +#endif + _BEGIN_STD_C _PTR _EXFUN(memchr,(const _PTR, int, size_t)); @@ -43,57 +51,43 @@ char *_EXFUN(strtok,(char *__restrict, const char *__restrict)); #endif size_t _EXFUN(strxfrm,(char *__restrict, const char *__restrict, size_t)); -#if __POSIX_VISIBLE +#if __POSIX_VISIBLE >= 200809 +int strcoll_l (const char *, const char *, locale_t); +char *strerror_l (int, locale_t); +size_t strxfrm_l (char *__restrict, const char *__restrict, size_t, locale_t); +#endif +#if __MISC_VISIBLE || __POSIX_VISIBLE char *_EXFUN(strtok_r,(char *__restrict, const char *__restrict, char **__restrict)); #endif #if __BSD_VISIBLE -int _EXFUN(bcmp,(const void *, const void *, size_t)); -void _EXFUN(bcopy,(const void *, void *, size_t)); -void _EXFUN(bzero,(void *, size_t)); -int _EXFUN(ffs,(int)); -char *_EXFUN(index,(const char *, int)); +int _EXFUN(timingsafe_bcmp,(const void *, const void *, size_t)); +int _EXFUN(timingsafe_memcmp,(const void *, const void *, size_t)); #endif -#if __BSD_VISIBLE || __XSI_VISIBLE +#if __MISC_VISIBLE || __POSIX_VISIBLE _PTR _EXFUN(memccpy,(_PTR __restrict, const _PTR __restrict, int, size_t)); #endif #if __GNU_VISIBLE _PTR _EXFUN(mempcpy,(_PTR, const _PTR, size_t)); _PTR _EXFUN(memmem, (const _PTR, size_t, const _PTR, size_t)); -#endif _PTR _EXFUN(memrchr,(const _PTR, int, size_t)); -#if __GNU_VISIBLE _PTR _EXFUN(rawmemchr,(const _PTR, int)); #endif -#if __BSD_VISIBLE -char *_EXFUN(rindex,(const char *, int)); -#endif +#if __POSIX_VISIBLE >= 200809 char *_EXFUN(stpcpy,(char *__restrict, const char *__restrict)); char *_EXFUN(stpncpy,(char *__restrict, const char *__restrict, size_t)); -#if __BSD_VISIBLE || __POSIX_VISIBLE -int _EXFUN(strcasecmp,(const char *, const char *)); #endif #if __GNU_VISIBLE char *_EXFUN(strcasestr,(const char *, const char *)); char *_EXFUN(strchrnul,(const char *, int)); #endif -#if __XSI_VISIBLE >= 500 +#if __MISC_VISIBLE || __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4 char *_EXFUN(strdup,(const char *)); #endif -#ifndef __STRICT_ANSI__ char *_EXFUN(_strdup_r,(struct _reent *, const char *)); -#endif -#if __XSI_VISIBLE >= 700 +#if __POSIX_VISIBLE >= 200809 char *_EXFUN(strndup,(const char *, size_t)); #endif - -#ifndef __STRICT_ANSI__ char *_EXFUN(_strndup_r,(struct _reent *, const char *, size_t)); -#endif - -#if __GNU_VISIBLE -int _EXFUN(ffsl,(long)); -int _EXFUN(ffsll, (long long)); -#endif /* There are two common strerror_r variants. If you request _GNU_SOURCE, you get the GNU version; otherwise you get the POSIX @@ -101,10 +95,13 @@ int _EXFUN(ffsll, (long long)); invoke the underlying function, but that requires gcc support. */ #if __GNU_VISIBLE char *_EXFUN(strerror_r,(int, char *, size_t)); -#else +#elif __POSIX_VISIBLE >= 200112 # ifdef __GNUC__ int _EXFUN(strerror_r,(int, char *, size_t)) - __asm__ (__ASMNAME ("__xpg_strerror_r")); +#ifdef __ASMNAME + __asm__ (__ASMNAME ("__xpg_strerror_r")) +#endif + ; # else int _EXFUN(__xpg_strerror_r,(int, char *, size_t)); # define strerror_r __xpg_strerror_r @@ -118,22 +115,17 @@ char * _EXFUN(_strerror_r, (struct _reent *, int, int, int *)); size_t _EXFUN(strlcat,(char *, const char *, size_t)); size_t _EXFUN(strlcpy,(char *, const char *, size_t)); #endif -#if __BSD_VISIBLE || __POSIX_VISIBLE -int _EXFUN(strncasecmp,(const char *, const char *, size_t)); -#endif -#if !defined(__STRICT_ANSI__) || __POSIX_VISIBLE >= 200809 || \ - __XSI_VISIBLE >= 700 +#if __POSIX_VISIBLE >= 200809 size_t _EXFUN(strnlen,(const char *, size_t)); #endif #if __BSD_VISIBLE char *_EXFUN(strsep,(char **, const char *)); #endif +#if __BSD_VISIBLE +char *strnstr(const char *, const char *, size_t) __pure; +#endif -/* - * The origin of these is unknown to me so I am conditionalizing them - * on __STRICT_ANSI__. Finetuning this is definitely needed. --joel - */ -#if !defined(__STRICT_ANSI__) +#if __MISC_VISIBLE char *_EXFUN(strlwr,(char *)); char *_EXFUN(strupr,(char *)); #endif @@ -146,19 +138,39 @@ char *_EXFUN(strsignal, (int __signo)); int _EXFUN(strtosigno, (const char *__name)); #endif -#if defined _GNU_SOURCE && defined __GNUC__ +#if __GNU_VISIBLE +int _EXFUN(strverscmp,(const char *, const char *)); +#endif + +#if __GNU_VISIBLE && defined(__GNUC__) #define strdupa(__s) \ - (__extension__ ({const char *__in = (__s); \ - size_t __len = strlen (__in) + 1; \ - char * __out = (char *) __builtin_alloca (__len); \ - (char *) memcpy (__out, __in, __len);})) + (__extension__ ({const char *__sin = (__s); \ + size_t __len = strlen (__sin) + 1; \ + char * __sout = (char *) __builtin_alloca (__len); \ + (char *) memcpy (__sout, __sin, __len);})) #define strndupa(__s, __n) \ - (__extension__ ({const char *__in = (__s); \ - size_t __len = strnlen (__in, (__n)) + 1; \ - char *__out = (char *) __builtin_alloca (__len); \ - __out[__len-1] = '\0'; \ - (char *) memcpy (__out, __in, __len-1);})) -#endif /* _GNU_SOURCE && __GNUC__ */ + (__extension__ ({const char *__sin = (__s); \ + size_t __len = strnlen (__sin, (__n)) + 1; \ + char *__sout = (char *) __builtin_alloca (__len); \ + __sout[__len-1] = '\0'; \ + (char *) memcpy (__sout, __sin, __len-1);})) +#endif /* __GNU_VISIBLE && __GNUC__ */ + +/* There are two common basename variants. If you do NOT #include + and you do + + #define _GNU_SOURCE + #include + + you get the GNU version. Otherwise you get the POSIX versionfor which you + should #include i for the function prototype. POSIX requires that + #undef basename will still let you invoke the underlying function. However, + this also implies that the POSIX version is used in this case. That's made + sure here. */ +#if __GNU_VISIBLE && !defined(basename) +# define basename basename +char *_EXFUN(__nonnull (1) basename,(const char *)) __asm__(__ASMNAME("__gnu_basename")); +#endif #include diff --git a/libc/xtensa-lx106-elf/include/strings.h b/libc/xtensa-lx106-elf/include/strings.h index 131d81d..122f2fc 100644 --- a/libc/xtensa-lx106-elf/include/strings.h +++ b/libc/xtensa-lx106-elf/include/strings.h @@ -1,35 +1,78 @@ -/* - * strings.h +/*- + * Copyright (c) 2002 Mike Barcroft + * All rights reserved. * - * Definitions for string operations. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/include/strings.h 272673 2014-10-07 04:54:11Z delphij $ */ #ifndef _STRINGS_H_ -#define _STRINGS_H_ +#define _STRINGS_H_ -#include "_ansi.h" -#include +#include +#include -#include /* for size_t */ +#if __POSIX_VISIBLE >= 200809 +#include +#endif -_BEGIN_STD_C +#ifndef _SIZE_T_DECLARED +typedef __size_t size_t; +#define _SIZE_T_DECLARED +#endif -#if !defined __STRICT_ANSI__ && _POSIX_VERSION < 200809L -/* - * Marked LEGACY in Open Group Base Specifications Issue 6/IEEE Std 1003.1-2004 - * Removed from Open Group Base Specifications Issue 7/IEEE Std 1003.1-2008 - */ -int _EXFUN(bcmp,(const void *, const void *, size_t)); -void _EXFUN(bcopy,(const void *, void *, size_t)); -void _EXFUN(bzero,(void *, size_t)); -char *_EXFUN(index,(const char *, int)); -char *_EXFUN(rindex,(const char *, int)); -#endif /* ! __STRICT_ANSI__ */ +__BEGIN_DECLS +#if __BSD_VISIBLE || __POSIX_VISIBLE <= 200112 +int bcmp(const void *, const void *, size_t) __pure; /* LEGACY */ +void bcopy(const void *, void *, size_t); /* LEGACY */ +void bzero(void *, size_t); /* LEGACY */ +#endif +#if __BSD_VISIBLE +void explicit_bzero(void *, size_t); +#endif +#if __MISC_VISIBLE || __POSIX_VISIBLE < 200809 || __XSI_VISIBLE >= 700 +int ffs(int) __pure2; +#endif +#if __GNU_VISIBLE +int ffsl(long) __pure2; +int ffsll(long long) __pure2; +#endif +#if __BSD_VISIBLE +int fls(int) __pure2; +int flsl(long) __pure2; +int flsll(long long) __pure2; +#endif +#if __BSD_VISIBLE || __POSIX_VISIBLE <= 200112 +char *index(const char *, int) __pure; /* LEGACY */ +char *rindex(const char *, int) __pure; /* LEGACY */ +#endif +int strcasecmp(const char *, const char *) __pure; +int strncasecmp(const char *, const char *, size_t) __pure; -int _EXFUN(ffs,(int)); -int _EXFUN(strcasecmp,(const char *, const char *)); -int _EXFUN(strncasecmp,(const char *, const char *, size_t)); - -_END_STD_C +#if __POSIX_VISIBLE >= 200809 +int strcasecmp_l (const char *, const char *, locale_t); +int strncasecmp_l (const char *, const char *, size_t, locale_t); +#endif +__END_DECLS #endif /* _STRINGS_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/_default_fcntl.h b/libc/xtensa-lx106-elf/include/sys/_default_fcntl.h index eb674ae..ede90c4 100644 --- a/libc/xtensa-lx106-elf/include/sys/_default_fcntl.h +++ b/libc/xtensa-lx106-elf/include/sys/_default_fcntl.h @@ -65,7 +65,7 @@ extern "C" { #define O_SEARCH _FEXECSRCH #endif -#ifndef _POSIX_SOURCE +#if __MISC_VISIBLE /* * Flags that work for fcntl(fd, F_SETFL, FXXXX) @@ -97,7 +97,11 @@ extern "C" { #define FEXCL _FEXCL #define FNOCTTY _FNOCTTY -#endif /* !_POSIX_SOURCE */ +#endif /* __MISC_VISIBLE */ + +#if __BSD_VISIBLE +#define FNONBLOCK _FNONBLOCK +#endif /* __BSD_VISIBLE */ /* XXX close on exec request; must match UF_EXCLOSE in user.h */ #define FD_CLOEXEC 1 /* posix */ @@ -108,20 +112,20 @@ extern "C" { #define F_SETFD 2 /* Set fildes flags (close on exec) */ #define F_GETFL 3 /* Get file flags */ #define F_SETFL 4 /* Set file flags */ -#ifndef _POSIX_SOURCE +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 #define F_GETOWN 5 /* Get owner - for ASYNC */ #define F_SETOWN 6 /* Set owner - for ASYNC */ -#endif /* !_POSIX_SOURCE */ +#endif /* __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 */ #define F_GETLK 7 /* Get record-locking information */ #define F_SETLK 8 /* Set or Clear a record-lock (Non-Blocking) */ #define F_SETLKW 9 /* Set or Clear a record-lock (Blocking) */ -#ifndef _POSIX_SOURCE +#if __MISC_VISIBLE #define F_RGETLK 10 /* Test a remote lock to see if it is blocked */ #define F_RSETLK 11 /* Set or unlock a remote lock */ #define F_CNVT 12 /* Convert a fhandle to an open fd */ #define F_RSETLKW 13 /* Set or Clear remote record-lock(Blocking) */ -#endif /* !_POSIX_SOURCE */ -#ifdef __CYGWIN__ +#endif /* __MISC_VISIBLE */ +#if __POSIX_VISIBLE >= 200809 #define F_DUPFD_CLOEXEC 14 /* As F_DUPFD, but set close-on-exec flag */ #endif @@ -129,11 +133,11 @@ extern "C" { #define F_RDLCK 1 /* read lock */ #define F_WRLCK 2 /* write lock */ #define F_UNLCK 3 /* remove lock(s) */ -#ifndef _POSIX_SOURCE +#if __MISC_VISIBLE #define F_UNLKSYS 4 /* remove remote locks for a given system */ -#endif /* !_POSIX_SOURCE */ +#endif /* __MISC_VISIBLE */ -#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 || defined(__CYGWIN__) +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 /* Special descriptor value to denote the cwd in calls to openat(2) etc. */ #define AT_FDCWD -2 @@ -166,7 +170,7 @@ struct flock { }; #endif /* __CYGWIN__ */ -#ifndef _POSIX_SOURCE +#if __MISC_VISIBLE /* extended file segment locking set data type */ struct eflock { short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */ @@ -178,13 +182,13 @@ struct eflock { long l_rpid; /* Remote process id wanting this lock */ long l_rsys; /* Remote system id wanting this lock */ }; -#endif /* !_POSIX_SOURCE */ +#endif /* __MISC_VISIBLE */ #include #include /* sigh. for the mode bits for open/creat */ extern int open _PARAMS ((const char *, int, ...)); -#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 || defined(__CYGWIN__) +#if __ATFILE_VISIBLE extern int openat _PARAMS ((int, const char *, int, ...)); #endif extern int creat _PARAMS ((const char *, mode_t)); @@ -192,7 +196,7 @@ extern int fcntl _PARAMS ((int, int, ...)); #if __BSD_VISIBLE extern int flock _PARAMS ((int, int)); #endif -#ifdef __CYGWIN__ +#if __GNU_VISIBLE #include extern int futimesat _PARAMS ((int, const char *, const struct timeval *)); #endif diff --git a/libc/xtensa-lx106-elf/include/sys/_intsup.h b/libc/xtensa-lx106-elf/include/sys/_intsup.h index fa78426..88d7400 100644 --- a/libc/xtensa-lx106-elf/include/sys/_intsup.h +++ b/libc/xtensa-lx106-elf/include/sys/_intsup.h @@ -4,8 +4,6 @@ * * Permission to use, copy, modify, and distribute this software * is freely granted, provided that this notice is preserved. - * - * Modified for xtensa arch & non-long int32_t, removes automatic setting of __have_long32. */ #ifndef _SYS__INTSUP_H @@ -13,8 +11,185 @@ #include +#if __GNUC_PREREQ (3, 2) +/* gcc > 3.2 implicitly defines the values we are interested */ #define __STDINT_EXP(x) __##x##__ +#else +#define __STDINT_EXP(x) x +#include +#endif -#define __have_longlong64 1 +/* Determine how intptr_t and intN_t fastN_t and leastN_t are defined by gcc + for this target. This is used to determine the correct printf() constant in + inttypes.h and other constants in stdint.h. + So we end up with + ?(signed|unsigned) char == 0 + ?(signed|unsigned) short == 1 + ?(signed|unsigned) int == 2 + ?(signed|unsigned) short int == 3 + ?(signed|unsigned) long == 4 + ?(signed|unsigned) long int == 6 + ?(signed|unsigned) long long == 8 + ?(signed|unsigned) long long int == 10 + */ +#pragma push_macro("signed") +#pragma push_macro("unsigned") +#pragma push_macro("char") +#pragma push_macro("short") +#pragma push_macro("__int20") +#pragma push_macro("int") +#pragma push_macro("long") +#undef signed +#undef unsigned +#undef char +#undef short +#undef int +#undef __int20 +#undef long +#define signed +0 +#define unsigned +0 +#define char +0 +#define short +1 +#define __int20 +2 +#define int +2 +#define long +4 +#if (__INTPTR_TYPE__ == 8 || __INTPTR_TYPE__ == 10) +#define _INTPTR_EQ_LONGLONG +#elif (__INTPTR_TYPE__ == 4 || __INTPTR_TYPE__ == 6) +#define _INTPTR_EQ_LONG +/* Note - the tests for _INTPTR_EQ_INT and _INTPTR_EQ_SHORT are currently + redundant as the values are not used. But one day they may be needed + and so the tests remain. */ +#elif __INTPTR_TYPE__ == 2 +#define _INTPTR_EQ_INT +#elif (__INTPTR_TYPE__ == 1 || __INTPTR_TYPE__ == 3) +#define _INTPTR_EQ_SHORT +#else +#error "Unable to determine type definition of intptr_t" +#endif +#if (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6) +#define _INT32_EQ_LONG +#elif __INT32_TYPE__ == 2 +/* Nothing to define because int32_t is safe to print as an int. */ +#else +#error "Unable to determine type definition of int32_t" +#endif + +#if (__INT8_TYPE__ == 0) +#define __INT8 "hh" +#elif (__INT8_TYPE__ == 1 || __INT8_TYPE__ == 3) +#define __INT8 "h" +#elif (__INT8_TYPE__ == 2) +#define __INT8 +#elif (__INT8_TYPE__ == 4 || __INT8_TYPE__ == 6) +#define __INT8 "l" +#elif (__INT8_TYPE__ == 8 || __INT8_TYPE__ == 10) +#define __INT8 "ll" +#endif +#if (__INT16_TYPE__ == 1 || __INT16_TYPE__ == 3) +#define __INT16 "h" +#elif (__INT16_TYPE__ == 2) +#define __INT16 +#elif (__INT16_TYPE__ == 4 || __INT16_TYPE__ == 6) +#define __INT16 "l" +#elif (__INT16_TYPE__ == 8 || __INT16_TYPE__ == 10) +#define __INT16 "ll" +#endif +#if (__INT32_TYPE__ == 2) +#define __INT32 +#elif (__INT32_TYPE__ == 4 || __INT32_TYPE__ == 6) +#define __INT32 "l" +#elif (__INT32_TYPE__ == 8 || __INT32_TYPE__ == 10) +#define __INT32 "ll" +#endif +#if (__INT64_TYPE__ == 2) +#define __INT64 +#elif (__INT64_TYPE__ == 4 || __INT64_TYPE__ == 6) +#define __INT64 "l" +#elif (__INT64_TYPE__ == 8 || __INT64_TYPE__ == 10) +#define __INT64 "ll" +#endif +#if (__INT_FAST8_TYPE__ == 0) +#define __FAST8 "hh" +#elif (__INT_FAST8_TYPE__ == 1 || __INT_FAST8_TYPE__ == 3) +#define __FAST8 "h" +#elif (__INT_FAST8_TYPE__ == 2) +#define __FAST8 +#elif (__INT_FAST8_TYPE__ == 4 || __INT_FAST8_TYPE__ == 6) +#define __FAST8 "l" +#elif (__INT_FAST8_TYPE__ == 8 || __INT_FAST8_TYPE__ == 10) +#define __FAST8 "ll" +#endif +#if (__INT_FAST16_TYPE__ == 1 || __INT_FAST16_TYPE__ == 3) +#define __FAST16 "h" +#elif (__INT_FAST16_TYPE__ == 2) +#define __FAST16 +#elif (__INT_FAST16_TYPE__ == 4 || __INT_FAST16_TYPE__ == 6) +#define __FAST16 "l" +#elif (__INT_FAST16_TYPE__ == 8 || __INT_FAST16_TYPE__ == 10) +#define __FAST16 "ll" +#endif +#if (__INT_FAST32_TYPE__ == 2) +#define __FAST32 +#elif (__INT_FAST32_TYPE__ == 4 || __INT_FAST32_TYPE__ == 6) +#define __FAST32 "l" +#elif (__INT_FAST32_TYPE__ == 8 || __INT_FAST32_TYPE__ == 10) +#define __FAST32 "ll" +#endif +#if (__INT_FAST64_TYPE__ == 2) +#define __FAST64 +#elif (__INT_FAST64_TYPE__ == 4 || __INT_FAST64_TYPE__ == 6) +#define __FAST64 "l" +#elif (__INT_FAST64_TYPE__ == 8 || __INT_FAST64_TYPE__ == 10) +#define __FAST64 "ll" +#endif + +#if (__INT_LEAST8_TYPE__ == 0) +#define __LEAST8 "hh" +#elif (__INT_LEAST8_TYPE__ == 1 || __INT_LEAST8_TYPE__ == 3) +#define __LEAST8 "h" +#elif (__INT_LEAST8_TYPE__ == 2) +#define __LEAST8 +#elif (__INT_LEAST8_TYPE__ == 4 || __INT_LEAST8_TYPE__ == 6) +#define __LEAST8 "l" +#elif (__INT_LEAST8_TYPE__ == 8 || __INT_LEAST8_TYPE__ == 10) +#define __LEAST8 "ll" +#endif +#if (__INT_LEAST16_TYPE__ == 1 || __INT_LEAST16_TYPE__ == 3) +#define __LEAST16 "h" +#elif (__INT_LEAST16_TYPE__ == 2) +#define __LEAST16 +#elif (__INT_LEAST16_TYPE__ == 4 || __INT_LEAST16_TYPE__ == 6) +#define __LEAST16 "l" +#elif (__INT_LEAST16_TYPE__ == 8 || __INT_LEAST16_TYPE__ == 10) +#define __LEAST16 "ll" +#endif +#if (__INT_LEAST32_TYPE__ == 2) +#define __LEAST32 +#elif (__INT_LEAST32_TYPE__ == 4 || __INT_LEAST32_TYPE__ == 6) +#define __LEAST32 "l" +#elif (__INT_LEAST32_TYPE__ == 8 || __INT_LEAST32_TYPE__ == 10) +#define __LEAST32 "ll" +#endif +#if (__INT_LEAST64_TYPE__ == 2) +#define __LEAST64 +#elif (__INT_LEAST64_TYPE__ == 4 || __INT_LEAST64_TYPE__ == 6) +#define __LEAST64 "l" +#elif (__INT_LEAST64_TYPE__ == 8 || __INT_LEAST64_TYPE__ == 10) +#define __LEAST64 "ll" +#endif +#undef signed +#undef unsigned +#undef char +#undef short +#undef int +#undef long +#pragma pop_macro("signed") +#pragma pop_macro("unsigned") +#pragma pop_macro("char") +#pragma pop_macro("short") +#pragma pop_macro("__int20") +#pragma pop_macro("int") +#pragma pop_macro("long") #endif /* _SYS__INTSUP_H */ diff --git a/libc/xtensa-lx106-elf/include/sys/_pthreadtypes.h b/libc/xtensa-lx106-elf/include/sys/_pthreadtypes.h new file mode 100644 index 0000000..75e9e1c --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/_pthreadtypes.h @@ -0,0 +1,233 @@ +/* + * Written by Joel Sherrill . + * + * COPYRIGHT (c) 1989-2013, 2015. + * On-Line Applications Research Corporation (OAR). + * + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION + * OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS + * SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ + +#ifndef _SYS__PTHREADTYPES_H_ +#define _SYS__PTHREADTYPES_H_ + +#if defined(_POSIX_THREADS) || __POSIX_VISIBLE >= 199506 + +#include + +/* + * 2.5 Primitive System Data Types, P1003.1c/D10, p. 19. + */ + +#if defined(__XMK__) +typedef unsigned int pthread_t; /* identify a thread */ +#else +typedef __uint32_t pthread_t; /* identify a thread */ +#endif + +/* P1003.1c/D10, p. 118-119 */ +#define PTHREAD_SCOPE_PROCESS 0 +#define PTHREAD_SCOPE_SYSTEM 1 + +/* P1003.1c/D10, p. 111 */ +#define PTHREAD_INHERIT_SCHED 1 /* scheduling policy and associated */ + /* attributes are inherited from */ + /* the calling thread. */ +#define PTHREAD_EXPLICIT_SCHED 2 /* set from provided attribute object */ + +/* P1003.1c/D10, p. 141 */ +#define PTHREAD_CREATE_DETACHED 0 +#define PTHREAD_CREATE_JOINABLE 1 + +#if defined(__XMK__) +typedef struct pthread_attr_s { + int contentionscope; + struct sched_param schedparam; + int detachstate; + void *stackaddr; + size_t stacksize; +} pthread_attr_t; + +#define PTHREAD_STACK_MIN 200 + +#else /* !defined(__XMK__) */ +typedef struct { + int is_initialized; + void *stackaddr; + int stacksize; + int contentionscope; + int inheritsched; + int schedpolicy; + struct sched_param schedparam; + + /* P1003.4b/D8, p. 54 adds cputime_clock_allowed attribute. */ +#if defined(_POSIX_THREAD_CPUTIME) + int cputime_clock_allowed; /* see time.h */ +#endif + int detachstate; +} pthread_attr_t; + +#endif /* !defined(__XMK__) */ + +#if defined(_POSIX_THREAD_PROCESS_SHARED) +/* NOTE: P1003.1c/D10, p. 81 defines following values for process_shared. */ + +#define PTHREAD_PROCESS_PRIVATE 0 /* visible within only the creating process */ +#define PTHREAD_PROCESS_SHARED 1 /* visible too all processes with access to */ + /* the memory where the resource is */ + /* located */ +#endif + +#if defined(_POSIX_THREAD_PRIO_PROTECT) +/* Mutexes */ + +/* Values for blocking protocol. */ + +#define PTHREAD_PRIO_NONE 0 +#define PTHREAD_PRIO_INHERIT 1 +#define PTHREAD_PRIO_PROTECT 2 +#endif + +#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) + +/* Values for mutex type */ + +/* The following defines are part of the X/Open System Interface (XSI). */ + +/* + * This type of mutex does not detect deadlock. A thread attempting to + * relock this mutex without first unlocking it shall deadlock. Attempting + * to unlock a mutex locked by a different thread results in undefined + * behavior. Attempting to unlock an unlocked mutex results in undefined + * behavior. + */ +#define PTHREAD_MUTEX_NORMAL 0 + +/* + * A thread attempting to relock this mutex without first unlocking + * it shall succeed in locking the mutex. The relocking deadlock which + * can occur with mutexes of type PTHREAD_MUTEX_NORMAL cannot occur with + * this type of mutex. Multiple locks of this mutex shall require the + * same number of unlocks to release the mutex before another thread can + * acquire the mutex. A thread attempting to unlock a mutex which another + * thread has locked shall return with an error. A thread attempting to + * unlock an unlocked mutex shall return with an error. + */ +#define PTHREAD_MUTEX_RECURSIVE 1 + +/* + * This type of mutex provides error checking. A thread attempting + * to relock this mutex without first unlocking it shall return with an + * error. A thread attempting to unlock a mutex which another thread has + * locked shall return with an error. A thread attempting to unlock an + * unlocked mutex shall return with an error. + */ +#define PTHREAD_MUTEX_ERRORCHECK 2 + +/* + * Attempting to recursively lock a mutex of this type results + * in undefined behavior. Attempting to unlock a mutex of this type + * which was not locked by the calling thread results in undefined + * behavior. Attempting to unlock a mutex of this type which is not locked + * results in undefined behavior. An implementation may map this mutex to + * one of the other mutex types. + */ +#define PTHREAD_MUTEX_DEFAULT 3 + +#endif /* !defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) */ + +#if defined(__XMK__) +typedef unsigned int pthread_mutex_t; /* identify a mutex */ + +typedef struct { + int type; +} pthread_mutexattr_t; + +#else /* !defined(__XMK__) */ +typedef __uint32_t pthread_mutex_t; /* identify a mutex */ + +typedef struct { + int is_initialized; +#if defined(_POSIX_THREAD_PROCESS_SHARED) + int process_shared; /* allow mutex to be shared amongst processes */ +#endif +#if defined(_POSIX_THREAD_PRIO_PROTECT) + int prio_ceiling; + int protocol; +#endif +#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) + int type; +#endif + int recursive; +} pthread_mutexattr_t; +#endif /* !defined(__XMK__) */ + +#define _PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) 0xFFFFFFFF) + +/* Condition Variables */ + +typedef __uint32_t pthread_cond_t; /* identify a condition variable */ + +#define _PTHREAD_COND_INITIALIZER ((pthread_cond_t) 0xFFFFFFFF) + +typedef struct { + int is_initialized; + clock_t clock; /* specifiy clock for timeouts */ +#if defined(_POSIX_THREAD_PROCESS_SHARED) + int process_shared; /* allow this to be shared amongst processes */ +#endif +} pthread_condattr_t; /* a condition attribute object */ + +/* Keys */ + +typedef __uint32_t pthread_key_t; /* thread-specific data keys */ + +typedef struct { + int is_initialized; /* is this structure initialized? */ + int init_executed; /* has the initialization routine been run? */ +} pthread_once_t; /* dynamic package initialization */ + +#define _PTHREAD_ONCE_INIT { 1, 0 } /* is initialized and not run */ +#endif /* defined(_POSIX_THREADS) || __POSIX_VISIBLE >= 199506 */ + +/* POSIX Barrier Types */ + +#if defined(_POSIX_BARRIERS) +typedef __uint32_t pthread_barrier_t; /* POSIX Barrier Object */ +typedef struct { + int is_initialized; /* is this structure initialized? */ +#if defined(_POSIX_THREAD_PROCESS_SHARED) + int process_shared; /* allow this to be shared amongst processes */ +#endif +} pthread_barrierattr_t; +#endif /* defined(_POSIX_BARRIERS) */ + +/* POSIX Spin Lock Types */ + +#if defined(_POSIX_SPIN_LOCKS) +typedef __uint32_t pthread_spinlock_t; /* POSIX Spin Lock Object */ +#endif /* defined(_POSIX_SPIN_LOCKS) */ + +/* POSIX Reader/Writer Lock Types */ + +#if defined(_POSIX_READER_WRITER_LOCKS) +typedef __uint32_t pthread_rwlock_t; /* POSIX RWLock Object */ + +#define _PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) 0xFFFFFFFF) + +typedef struct { + int is_initialized; /* is this structure initialized? */ +#if defined(_POSIX_THREAD_PROCESS_SHARED) + int process_shared; /* allow this to be shared amongst processes */ +#endif +} pthread_rwlockattr_t; +#endif /* defined(_POSIX_READER_WRITER_LOCKS) */ + +#endif /* ! _SYS__PTHREADTYPES_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/_sigset.h b/libc/xtensa-lx106-elf/include/sys/_sigset.h new file mode 100644 index 0000000..a9c0d2d --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/_sigset.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 1982, 1986, 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)signal.h 8.4 (Berkeley) 5/4/95 + * $FreeBSD$ + */ + +#ifndef _SYS__SIGSET_H_ +#define _SYS__SIGSET_H_ + +typedef unsigned long __sigset_t; + +#endif /* !_SYS__SIGSET_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/_stdint.h b/libc/xtensa-lx106-elf/include/sys/_stdint.h new file mode 100644 index 0000000..21a14d3 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/_stdint.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2004, 2005 by + * Ralf Corsepius, Ulm/Germany. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software + * is freely granted, provided that this notice is preserved. + */ + +#ifndef _SYS__STDINT_H +#define _SYS__STDINT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ___int8_t_defined +#ifndef _INT8_T_DECLARED +typedef __int8_t int8_t ; +#define _INT8_T_DECLARED +#endif +#ifndef _UINT8_T_DECLARED +typedef __uint8_t uint8_t ; +#define _UINT8_T_DECLARED +#endif +#define __int8_t_defined 1 +#endif /* ___int8_t_defined */ + +#ifdef ___int16_t_defined +#ifndef _INT16_T_DECLARED +typedef __int16_t int16_t ; +#define _INT16_T_DECLARED +#endif +#ifndef _UINT16_T_DECLARED +typedef __uint16_t uint16_t ; +#define _UINT16_T_DECLARED +#endif +#define __int16_t_defined 1 +#endif /* ___int16_t_defined */ + +#ifdef ___int32_t_defined +#ifndef _INT32_T_DECLARED +typedef __int32_t int32_t ; +#define _INT32_T_DECLARED +#endif +#ifndef _UINT32_T_DECLARED +typedef __uint32_t uint32_t ; +#define _UINT32_T_DECLARED +#endif +#define __int32_t_defined 1 +#endif /* ___int32_t_defined */ + +#ifdef ___int64_t_defined +#ifndef _INT64_T_DECLARED +typedef __int64_t int64_t ; +#define _INT64_T_DECLARED +#endif +#ifndef _UINT64_T_DECLARED +typedef __uint64_t uint64_t ; +#define _UINT64_T_DECLARED +#endif +#define __int64_t_defined 1 +#endif /* ___int64_t_defined */ + +#ifndef _INTMAX_T_DECLARED +typedef __intmax_t intmax_t; +#define _INTMAX_T_DECLARED +#endif + +#ifndef _UINTMAX_T_DECLARED +typedef __uintmax_t uintmax_t; +#define _UINTMAX_T_DECLARED +#endif + +#ifndef _INTPTR_T_DECLARED +typedef __intptr_t intptr_t; +#define _INTPTR_T_DECLARED +#endif + +#ifndef _UINTPTR_T_DECLARED +typedef __uintptr_t uintptr_t; +#define _UINTPTR_T_DECLARED +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS__STDINT_H */ diff --git a/libc/xtensa-lx106-elf/include/sys/_timespec.h b/libc/xtensa-lx106-elf/include/sys/_timespec.h new file mode 100644 index 0000000..7609e4a --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/_timespec.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)time.h 8.5 (Berkeley) 5/4/95 + * from: FreeBSD: src/sys/sys/time.h,v 1.43 2000/03/20 14:09:05 phk Exp + * $FreeBSD$ + */ + +#ifndef _SYS__TIMESPEC_H_ +#define _SYS__TIMESPEC_H_ + +#include + +#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED) +typedef _TIME_T_ time_t; +#define __time_t_defined +#define _TIME_T_DECLARED +#endif + +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; + +#endif /* !_SYS__TIMESPEC_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/_timeval.h b/libc/xtensa-lx106-elf/include/sys/_timeval.h new file mode 100644 index 0000000..676a0b8 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/_timeval.h @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2002 Mike Barcroft + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS__TIMEVAL_H_ +#define _SYS__TIMEVAL_H_ + +#include + +#ifndef _SUSECONDS_T_DECLARED +typedef __suseconds_t suseconds_t; +#define _SUSECONDS_T_DECLARED +#endif + +#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED) +typedef _TIME_T_ time_t; +#define __time_t_defined +#define _TIME_T_DECLARED +#endif + +/* This define is also used outside of Newlib, e.g. in MinGW-w64 */ +#ifndef _TIMEVAL_DEFINED +#define _TIMEVAL_DEFINED + +/* + * Structure returned by gettimeofday(2) system call, and used in other calls. + */ +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* and microseconds */ +}; + +#if __BSD_VISIBLE +#ifndef _KERNEL /* NetBSD/OpenBSD compatible interfaces */ + +#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) +#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) +#define timercmp(tvp, uvp, cmp) \ + (((tvp)->tv_sec == (uvp)->tv_sec) ? \ + ((tvp)->tv_usec cmp (uvp)->tv_usec) : \ + ((tvp)->tv_sec cmp (uvp)->tv_sec)) +#define timeradd(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) +#endif +#endif /* __BSD_VISIBLE */ + +#endif /* _TIMEVAL_DEFINED */ + +#endif /* !_SYS__TIMEVAL_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/_types.h b/libc/xtensa-lx106-elf/include/sys/_types.h index 07bc276..72e1dc1 100644 --- a/libc/xtensa-lx106-elf/include/sys/_types.h +++ b/libc/xtensa-lx106-elf/include/sys/_types.h @@ -2,51 +2,141 @@ /* This file defines various typedefs needed by the system calls that support the C library. Basically, they're just the POSIX versions with an '_' - prepended. This file lives in the `sys' directory so targets can provide - their own if desired (or they can put target dependant conditionals here). + prepended. Targets shall use to define their own + internal types if desired. + + There are three define patterns used for type definitions. Lets assume + xyz_t is a user type. + + The internal type definition uses __machine_xyz_t_defined. It is defined by + to disable a default definition in . It + must not be used in other files. + + User type definitions are guarded by __xyz_t_defined in glibc and + _XYZ_T_DECLARED in BSD compatible systems. */ #ifndef _SYS__TYPES_H #define _SYS__TYPES_H +#include +#include #include #include -#ifndef __off_t_defined +#ifndef __machine_blkcnt_t_defined +typedef long __blkcnt_t; +#endif + +#ifndef __machine_blksize_t_defined +typedef long __blksize_t; +#endif + +#ifndef __machine_fsblkcnt_t_defined +typedef __uint64_t __fsblkcnt_t; +#endif + +#ifndef __machine_fsfilcnt_t_defined +typedef __uint32_t __fsfilcnt_t; +#endif + +#ifndef __machine_off_t_defined typedef long _off_t; #endif -#ifndef __dev_t_defined +#if defined(__XMK__) +typedef signed char __pid_t; +#else +typedef int __pid_t; +#endif + +#ifndef __machine_dev_t_defined typedef short __dev_t; #endif -#ifndef __uid_t_defined +#ifndef __machine_uid_t_defined typedef unsigned short __uid_t; #endif -#ifndef __gid_t_defined +#ifndef __machine_gid_t_defined typedef unsigned short __gid_t; #endif -#ifndef __off64_t_defined +#ifndef __machine_id_t_defined +typedef __uint32_t __id_t; +#endif + +#ifndef __machine_ino_t_defined +#if (defined(__i386__) && (defined(GO32) || defined(__MSDOS__))) || \ + defined(__sparc__) || defined(__SPU__) +typedef unsigned long __ino_t; +#else +typedef unsigned short __ino_t; +#endif +#endif + +#ifndef __machine_mode_t_defined +#if defined(__i386__) && (defined(GO32) || defined(__MSDOS__)) +typedef int __mode_t; +#else +#if defined(__sparc__) && !defined(__sparc_v9__) +#ifdef __svr4__ +typedef unsigned long __mode_t; +#else +typedef unsigned short __mode_t; +#endif +#else +typedef __uint32_t __mode_t; +#endif +#endif +#endif + +#ifndef __machine_off64_t_defined __extension__ typedef long long _off64_t; #endif +#if defined(__CYGWIN__) && !defined(__LP64__) +typedef _off64_t __off_t; +#else +typedef _off_t __off_t; +#endif + +typedef _off64_t __loff_t; + +#ifndef __machine_key_t_defined +typedef long __key_t; +#endif + /* * We need fpos_t for the following, but it doesn't have a leading "_", * so we use _fpos_t instead. */ -#ifndef __fpos_t_defined +#ifndef __machine_fpos_t_defined typedef long _fpos_t; /* XXX must match off_t in */ /* (and must be `long' for now) */ #endif #ifdef __LARGE64_FILES -#ifndef __fpos64_t_defined +#ifndef __machine_fpos64_t_defined typedef _off64_t _fpos64_t; #endif #endif -#ifndef __ssize_t_defined +/* Defined by GCC provided */ +#undef __size_t + +#ifndef __machine_size_t_defined +#ifdef __SIZE_TYPE__ +typedef __SIZE_TYPE__ __size_t; +#else +#if defined(__INT_MAX__) && __INT_MAX__ == 2147483647 +typedef unsigned int __size_t; +#else +typedef unsigned long __size_t; +#endif +#endif +#endif + +#ifndef __machine_ssize_t_defined #ifdef __SIZE_TYPE__ /* If __SIZE_TYPE__ is defined (gcc) we define ssize_t based on size_t. We simply change "unsigned" to "signed" for this single definition @@ -63,10 +153,12 @@ typedef long _ssize_t; #endif #endif +typedef _ssize_t __ssize_t; + #define __need_wint_t #include -#ifndef __mbstate_t_defined +#ifndef __machine_mbstate_t_defined /* Conversion state information. */ typedef struct { @@ -79,13 +171,50 @@ typedef struct } _mbstate_t; #endif -#ifndef __flock_t_defined +#ifndef __machine_flock_t_defined typedef _LOCK_RECURSIVE_T _flock_t; #endif -#ifndef __iconv_t_defined +#ifndef __machine_iconv_t_defined /* Iconv descriptor type */ typedef void *_iconv_t; #endif +#ifndef __machine_clock_t_defined +#define _CLOCK_T_ unsigned long /* clock() */ +#endif + +typedef _CLOCK_T_ __clock_t; + +#if defined(_USE_LONG_TIME_T) || __LONG_MAX__ > 0x7fffffffL +#define _TIME_T_ long +#else +#define _TIME_T_ __int_least64_t +#endif +typedef _TIME_T_ __time_t; + +#define _CLOCKID_T_ unsigned long +typedef _CLOCKID_T_ __clockid_t; + +#define _TIMER_T_ unsigned long +typedef _TIMER_T_ __timer_t; + +#ifndef __machine_sa_family_t_defined +typedef __uint8_t __sa_family_t; +#endif + +#ifndef __machine_socklen_t_defined +typedef __uint32_t __socklen_t; +#endif + +typedef unsigned short __nlink_t; +typedef long __suseconds_t; /* microseconds (signed) */ +typedef unsigned long __useconds_t; /* microseconds (unsigned) */ + +#ifdef __GNUCLIKE_BUILTIN_VARARGS +typedef __builtin_va_list __va_list; +#else +typedef char * __va_list; +#endif /* __GNUCLIKE_BUILTIN_VARARGS */ + #endif /* _SYS__TYPES_H */ diff --git a/libc/xtensa-lx106-elf/include/sys/cdefs.h b/libc/xtensa-lx106-elf/include/sys/cdefs.h index a5e613c..8ce14b6 100644 --- a/libc/xtensa-lx106-elf/include/sys/cdefs.h +++ b/libc/xtensa-lx106-elf/include/sys/cdefs.h @@ -17,7 +17,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -69,7 +69,9 @@ /* * Testing against Clang-specific extensions. */ - +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif #ifndef __has_extension #define __has_extension __has_feature #endif @@ -100,33 +102,33 @@ #if defined(__GNUC__) || defined(__INTEL_COMPILER) #if __GNUC__ >= 3 || defined(__INTEL_COMPILER) -#define __GNUCLIKE_ASM 3 -#define __GNUCLIKE_MATH_BUILTIN_CONSTANTS +#define __GNUCLIKE_ASM 3 +#define __GNUCLIKE_MATH_BUILTIN_CONSTANTS #else -#define __GNUCLIKE_ASM 2 +#define __GNUCLIKE_ASM 2 #endif -#define __GNUCLIKE___TYPEOF 1 -#define __GNUCLIKE___OFFSETOF 1 -#define __GNUCLIKE___SECTION 1 +#define __GNUCLIKE___TYPEOF 1 +#define __GNUCLIKE___OFFSETOF 1 +#define __GNUCLIKE___SECTION 1 #ifndef __INTEL_COMPILER -# define __GNUCLIKE_CTOR_SECTION_HANDLING 1 +#define __GNUCLIKE_CTOR_SECTION_HANDLING 1 #endif -#define __GNUCLIKE_BUILTIN_CONSTANT_P 1 -# if defined(__INTEL_COMPILER) && defined(__cplusplus) \ - && __INTEL_COMPILER < 800 -# undef __GNUCLIKE_BUILTIN_CONSTANT_P -# endif +#define __GNUCLIKE_BUILTIN_CONSTANT_P 1 +#if defined(__INTEL_COMPILER) && defined(__cplusplus) && \ + __INTEL_COMPILER < 800 +#undef __GNUCLIKE_BUILTIN_CONSTANT_P +#endif -#if (__GNUC_MINOR__ > 95 || __GNUC__ >= 3) && !defined(__INTEL_COMPILER) -# define __GNUCLIKE_BUILTIN_VARARGS 1 -# define __GNUCLIKE_BUILTIN_STDARG 1 -# define __GNUCLIKE_BUILTIN_VAALIST 1 +#if (__GNUC_MINOR__ > 95 || __GNUC__ >= 3) +#define __GNUCLIKE_BUILTIN_VARARGS 1 +#define __GNUCLIKE_BUILTIN_STDARG 1 +#define __GNUCLIKE_BUILTIN_VAALIST 1 #endif #if defined(__GNUC__) -# define __GNUC_VA_LIST_COMPATIBILITY 1 +#define __GNUC_VA_LIST_COMPATIBILITY 1 #endif /* @@ -137,23 +139,23 @@ #endif #ifndef __INTEL_COMPILER -# define __GNUCLIKE_BUILTIN_NEXT_ARG 1 -# define __GNUCLIKE_MATH_BUILTIN_RELOPS +#define __GNUCLIKE_BUILTIN_NEXT_ARG 1 +#define __GNUCLIKE_MATH_BUILTIN_RELOPS #endif -#define __GNUCLIKE_BUILTIN_MEMCPY 1 +#define __GNUCLIKE_BUILTIN_MEMCPY 1 /* XXX: if __GNUC__ >= 2: not tested everywhere originally, where replaced */ -#define __CC_SUPPORTS_INLINE 1 -#define __CC_SUPPORTS___INLINE 1 -#define __CC_SUPPORTS___INLINE__ 1 +#define __CC_SUPPORTS_INLINE 1 +#define __CC_SUPPORTS___INLINE 1 +#define __CC_SUPPORTS___INLINE__ 1 -#define __CC_SUPPORTS___FUNC__ 1 -#define __CC_SUPPORTS_WARNING 1 +#define __CC_SUPPORTS___FUNC__ 1 +#define __CC_SUPPORTS_WARNING 1 -#define __CC_SUPPORTS_VARADIC_XXX 1 /* see varargs.h */ +#define __CC_SUPPORTS_VARADIC_XXX 1 /* see varargs.h */ -#define __CC_SUPPORTS_DYNAMIC_ARRAY_INIT 1 +#define __CC_SUPPORTS_DYNAMIC_ARRAY_INIT 1 #endif /* __GNUC__ || __INTEL_COMPILER */ @@ -229,8 +231,12 @@ #define __unused #define __packed #define __aligned(x) +#define __alloc_align(x) +#define __alloc_size(x) #define __section(x) +#define __weak_symbol #else +#define __weak_symbol __attribute__((__weak__)) #if !__GNUC_PREREQ__(2, 5) && !defined(__INTEL_COMPILER) #define __dead2 #define __pure2 @@ -242,7 +248,7 @@ #define __unused /* XXX Find out what to do for __packed, __aligned and __section */ #endif -#if __GNUC_PREREQ__(2, 7) +#if __GNUC_PREREQ__(2, 7) || defined(__INTEL_COMPILER) #define __dead2 __attribute__((__noreturn__)) #define __pure2 __attribute__((__const__)) #define __unused __attribute__((__unused__)) @@ -251,16 +257,17 @@ #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) #endif -#if defined(__INTEL_COMPILER) -#define __dead2 __attribute__((__noreturn__)) -#define __pure2 __attribute__((__const__)) -#define __unused __attribute__((__unused__)) -#define __used __attribute__((__used__)) -#define __packed __attribute__((__packed__)) -#define __aligned(x) __attribute__((__aligned__(x))) -#define __section(x) __attribute__((__section__(x))) +#if __GNUC_PREREQ__(4, 3) || __has_attribute(__alloc_size__) +#define __alloc_size(x) __attribute__((__alloc_size__(x))) +#else +#define __alloc_size(x) #endif +#if __GNUC_PREREQ__(4, 9) || __has_attribute(__alloc_align__) +#define __alloc_align(x) __attribute__((__alloc_align__(x))) +#else +#define __alloc_align(x) #endif +#endif /* lint */ #if !__GNUC_PREREQ__(2, 95) #define __alignof(x) __offsetof(struct { char __a; x __b; }, __b) @@ -270,7 +277,7 @@ * Keywords added in C11. */ -#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L +#if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L || defined(lint) #if !__has_extension(c_alignas) #if (defined(__cplusplus) && __cplusplus >= 201103L) || \ @@ -288,7 +295,8 @@ #define _Alignof(x) __alignof(x) #endif -#if !__has_extension(c_atomic) && !__has_extension(cxx_atomic) +#if !defined(__cplusplus) && !__has_extension(c_atomic) && \ + !__has_extension(cxx_atomic) /* * No native support for _Atomic(). Place object in structure to prevent * most forms of direct non-atomic access. @@ -302,23 +310,28 @@ #define _Noreturn __dead2 #endif -#if __GNUC_PREREQ__(4, 6) && !defined(__cplusplus) -/* Do nothing: _Static_assert() works as per C11 */ -#elif !__has_extension(c_static_assert) +#if !__has_extension(c_static_assert) #if (defined(__cplusplus) && __cplusplus >= 201103L) || \ __has_extension(cxx_static_assert) #define _Static_assert(x, y) static_assert(x, y) +#elif __GNUC_PREREQ__(4,6) +/* Nothing, gcc 4.6 and higher has _Static_assert built-in */ #elif defined(__COUNTER__) #define _Static_assert(x, y) __Static_assert(x, __COUNTER__) #define __Static_assert(x, y) ___Static_assert(x, y) -#define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] +#define ___Static_assert(x, y) typedef char __assert_ ## y[(x) ? 1 : -1] \ + __unused #else #define _Static_assert(x, y) struct __hack #endif #endif #if !__has_extension(c_thread_local) -/* XXX: Change this to test against C++11 when clang in base supports it. */ +/* + * XXX: Some compilers (Clang 3.3, GCC 4.7) falsely announce C++11 mode + * without actually supporting the thread_local keyword. Don't check for + * the presence of C++11 when defining _Thread_local. + */ #if /* (defined(__cplusplus) && __cplusplus >= 201103L) || */ \ __has_extension(cxx_thread_local) #define _Thread_local thread_local @@ -338,7 +351,8 @@ * distinguish multiple cases. */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ + __has_extension(c_generic_selections) #define __generic(expr, t, yes, no) \ _Generic(expr, t: yes, default: no) #elif __GNUC_PREREQ__(3, 1) && !defined(__cplusplus) @@ -347,6 +361,21 @@ __builtin_types_compatible_p(__typeof(expr), t), yes, no) #endif +/* + * C99 Static array indices in function parameter declarations. Syntax such as: + * void bar(int myArray[static 10]); + * is allowed in C99 but not in C++. Define __min_size appropriately so + * headers using it can be compiled in either language. Use like this: + * void bar(int myArray[__min_size(10)]); + */ +#if !defined(__cplusplus) && \ + (defined(__clang__) || __GNUC_PREREQ__(4, 6)) && \ + (!defined(__STDC_VERSION__) || (__STDC_VERSION__ >= 199901)) +#define __min_size(x) static (x) +#else +#define __min_size(x) (x) +#endif + #if __GNUC_PREREQ__(2, 96) #define __malloc_like __attribute__((__malloc__)) #define __pure __attribute__((__pure__)) @@ -368,15 +397,19 @@ #endif #if __GNUC_PREREQ__(3, 3) -#define __nonnull(x) __attribute__((__nonnull__(x))) +#define __nonnull(x) __attribute__((__nonnull__(x))) +#define __nonnull_all __attribute__((__nonnull__)) #else -#define __nonnull(x) +#define __nonnull(x) +#define __nonnull_all #endif #if __GNUC_PREREQ__(3, 4) #define __fastcall __attribute__((__fastcall__)) +#define __result_use_check __attribute__((__warn_unused_result__)) #else #define __fastcall +#define __result_use_check #endif #if __GNUC_PREREQ__(4, 1) @@ -385,6 +418,12 @@ #define __returns_twice #endif +#if __GNUC_PREREQ__(4, 6) || __has_builtin(__builtin_unreachable) +#define __unreachable() __builtin_unreachable() +#else +#define __unreachable() ((void)0) +#endif + /* XXX: should use `#if __STDC_VERSION__ < 199901'. */ #if !__GNUC_PREREQ__(2, 7) && !defined(__INTEL_COMPILER) #define __func__ NULL @@ -433,19 +472,26 @@ * larger code. */ #if __GNUC_PREREQ__(2, 96) -#define __predict_true(exp) __builtin_expect((exp), 1) -#define __predict_false(exp) __builtin_expect((exp), 0) +#define __predict_true(exp) __builtin_expect((exp), 1) +#define __predict_false(exp) __builtin_expect((exp), 0) #else -#define __predict_true(exp) (exp) -#define __predict_false(exp) (exp) +#define __predict_true(exp) (exp) +#define __predict_false(exp) (exp) #endif -#if __GNUC_PREREQ__(4, 2) -#define __hidden __attribute__((__visibility__("hidden"))) +#if __GNUC_PREREQ__(4, 0) +#define __null_sentinel __attribute__((__sentinel__)) #define __exported __attribute__((__visibility__("default"))) +/* Only default visibility is supported on PE/COFF targets. */ +#ifndef __CYGWIN__ +#define __hidden __attribute__((__visibility__("hidden"))) #else #define __hidden +#endif +#else +#define __null_sentinel #define __exported +#define __hidden #endif #define __offsetof(type, field) offsetof(type, field) @@ -460,7 +506,7 @@ */ #if __GNUC_PREREQ__(3, 1) #define __containerof(x, s, m) ({ \ - const volatile __typeof__(((s *)0)->m) *__x = (x); \ + const volatile __typeof(((s *)0)->m) *__x = (x); \ __DEQUALIFY(s *, (const volatile char *)__x - __offsetof(s, m));\ }) #else @@ -583,128 +629,96 @@ #define __DEQUALIFY(type, var) ((type)(__uintptr_t)(const volatile void *)(var)) #endif -/*- - * The following definitions are an extension of the behavior originally - * implemented in , but with a different level of granularity. - * POSIX.1 requires that the macros we test be defined before any standard - * header file is included. - * - * Here's a quick run-down of the versions: - * defined(_POSIX_SOURCE) 1003.1-1988 - * _POSIX_C_SOURCE == 1 1003.1-1990 - * _POSIX_C_SOURCE == 2 1003.2-1992 C Language Binding Option - * _POSIX_C_SOURCE == 199309 1003.1b-1993 - * _POSIX_C_SOURCE == 199506 1003.1c-1995, 1003.1i-1995, - * and the omnibus ISO/IEC 9945-1: 1996 - * _POSIX_C_SOURCE == 200112 1003.1-2001 - * _POSIX_C_SOURCE == 200809 1003.1-2008 - * - * In addition, the X/Open Portability Guide, which is now the Single UNIX - * Specification, defines a feature-test macro which indicates the version of - * that specification, and which subsumes _POSIX_C_SOURCE. - * - * Our macros begin with two underscores to avoid namespace screwage. +/* + * Nullability qualifiers: currently only supported by Clang. */ - -/* Deal with IEEE Std. 1003.1-1990, in which _POSIX_C_SOURCE == 1. */ -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 1 -#undef _POSIX_C_SOURCE /* Probably illegal, but beyond caring now. */ -#define _POSIX_C_SOURCE 199009 -#endif - -/* Deal with IEEE Std. 1003.2-1992, in which _POSIX_C_SOURCE == 2. */ -#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE == 2 -#undef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 199209 -#endif - -/* Deal with various X/Open Portability Guides and Single UNIX Spec. */ -#ifdef _XOPEN_SOURCE -#if _XOPEN_SOURCE - 0 >= 700 -#define __XSI_VISIBLE 700 -#undef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809 -#elif _XOPEN_SOURCE - 0 >= 600 -#define __XSI_VISIBLE 600 -#undef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200112 -#elif _XOPEN_SOURCE - 0 >= 500 -#define __XSI_VISIBLE 500 -#undef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 199506 -#endif +#if !(defined(__clang__) && __has_feature(nullability)) +#define _Nonnull +#define _Nullable +#define _Null_unspecified +#define __NULLABILITY_PRAGMA_PUSH +#define __NULLABILITY_PRAGMA_POP +#else +#define __NULLABILITY_PRAGMA_PUSH _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wnullability-completeness\"") +#define __NULLABILITY_PRAGMA_POP _Pragma("clang diagnostic pop") #endif /* - * Deal with all versions of POSIX. The ordering relative to the tests above is - * important. - */ -#if defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) -#define _POSIX_C_SOURCE 198808 -#endif -#ifdef _POSIX_C_SOURCE -#if _POSIX_C_SOURCE >= 200809 -#define __POSIX_VISIBLE 200809 -#define __ISO_C_VISIBLE 1999 -#elif _POSIX_C_SOURCE >= 200112 -#define __POSIX_VISIBLE 200112 -#define __ISO_C_VISIBLE 1999 -#elif _POSIX_C_SOURCE >= 199506 -#define __POSIX_VISIBLE 199506 -#define __ISO_C_VISIBLE 1990 -#elif _POSIX_C_SOURCE >= 199309 -#define __POSIX_VISIBLE 199309 -#define __ISO_C_VISIBLE 1990 -#elif _POSIX_C_SOURCE >= 199209 -#define __POSIX_VISIBLE 199209 -#define __ISO_C_VISIBLE 1990 -#elif _POSIX_C_SOURCE >= 199009 -#define __POSIX_VISIBLE 199009 -#define __ISO_C_VISIBLE 1990 -#else -#define __POSIX_VISIBLE 198808 -#define __ISO_C_VISIBLE 0 -#endif /* _POSIX_C_SOURCE */ -#else -/*- - * Deal with _ANSI_SOURCE: - * If it is defined, and no other compilation environment is explicitly - * requested, then define our internal feature-test macros to zero. This - * makes no difference to the preprocessor (undefined symbols in preprocessing - * expressions are defined to have value zero), but makes it more convenient for - * a test program to print out the values. + * Type Safety Checking * - * If a program mistakenly defines _ANSI_SOURCE and some other macro such as - * _POSIX_C_SOURCE, we will assume that it wants the broader compilation - * environment (and in fact we will never get here). + * Clang provides additional attributes to enable checking type safety + * properties that cannot be enforced by the C type system. */ -#if defined(_ANSI_SOURCE) /* Hide almost everything. */ -#define __POSIX_VISIBLE 0 -#define __XSI_VISIBLE 0 -#define __BSD_VISIBLE 0 -#define __ISO_C_VISIBLE 1990 -#elif defined(_C99_SOURCE) /* Localism to specify strict C99 env. */ -#define __POSIX_VISIBLE 0 -#define __XSI_VISIBLE 0 -#define __BSD_VISIBLE 0 -#define __ISO_C_VISIBLE 1999 -#elif defined(_C11_SOURCE) /* Localism to specify strict C11 env. */ -#define __POSIX_VISIBLE 0 -#define __XSI_VISIBLE 0 -#define __BSD_VISIBLE 0 -#define __ISO_C_VISIBLE 2011 -#elif defined(_GNU_SOURCE) /* Everything and the kitchen sink. */ -#define __POSIX_VISIBLE 200809 -#define __XSI_VISIBLE 700 -#define __BSD_VISIBLE 1 -#define __ISO_C_VISIBLE 2011 -#define __GNU_VISIBLE 1 -#else /* Default: everything except __GNU_VISIBLE. */ -#define __POSIX_VISIBLE 200809 -#define __XSI_VISIBLE 700 -#define __BSD_VISIBLE 1 -#define __ISO_C_VISIBLE 2011 -#endif + +#if __has_attribute(__argument_with_type_tag__) && \ + __has_attribute(__type_tag_for_datatype__) && !defined(lint) +#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) \ + __attribute__((__argument_with_type_tag__(arg_kind, arg_idx, type_tag_idx))) +#define __datatype_type_tag(kind, type) \ + __attribute__((__type_tag_for_datatype__(kind, type))) +#else +#define __arg_type_tag(arg_kind, arg_idx, type_tag_idx) +#define __datatype_type_tag(kind, type) #endif +/* + * Lock annotations. + * + * Clang provides support for doing basic thread-safety tests at + * compile-time, by marking which locks will/should be held when + * entering/leaving a functions. + * + * Furthermore, it is also possible to annotate variables and structure + * members to enforce that they are only accessed when certain locks are + * held. + */ + +#if __has_extension(c_thread_safety_attributes) +#define __lock_annotate(x) __attribute__((x)) +#else +#define __lock_annotate(x) +#endif + +/* Structure implements a lock. */ +/* FIXME: Use __lockable__, etc. to avoid colliding with user namespace macros, + * once clang is fixed: https://bugs.llvm.org/show_bug.cgi?id=34319 */ +#define __lockable __lock_annotate(lockable) + +/* Function acquires an exclusive or shared lock. */ +#define __locks_exclusive(...) \ + __lock_annotate(exclusive_lock_function(__VA_ARGS__)) +#define __locks_shared(...) \ + __lock_annotate(shared_lock_function(__VA_ARGS__)) + +/* Function attempts to acquire an exclusive or shared lock. */ +#define __trylocks_exclusive(...) \ + __lock_annotate(exclusive_trylock_function(__VA_ARGS__)) +#define __trylocks_shared(...) \ + __lock_annotate(shared_trylock_function(__VA_ARGS__)) + +/* Function releases a lock. */ +#define __unlocks(...) __lock_annotate(unlock_function(__VA_ARGS__)) + +/* Function asserts that an exclusive or shared lock is held. */ +#define __asserts_exclusive(...) \ + __lock_annotate(assert_exclusive_lock(__VA_ARGS__)) +#define __asserts_shared(...) \ + __lock_annotate(assert_shared_lock(__VA_ARGS__)) + +/* Function requires that an exclusive or shared lock is or is not held. */ +#define __requires_exclusive(...) \ + __lock_annotate(exclusive_locks_required(__VA_ARGS__)) +#define __requires_shared(...) \ + __lock_annotate(shared_locks_required(__VA_ARGS__)) +#define __requires_unlocked(...) \ + __lock_annotate(locks_excluded(__VA_ARGS__)) + +/* Function should not be analyzed. */ +#define __no_lock_analysis __lock_annotate(no_thread_safety_analysis) + +/* Guard variables and structure members by lock. */ +#define __guarded_by(x) __lock_annotate(guarded_by(x)) +#define __pt_guarded_by(x) __lock_annotate(pt_guarded_by(x)) + #endif /* !_SYS_CDEFS_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/config.h b/libc/xtensa-lx106-elf/include/sys/config.h index f6f923e..3c185ea 100644 --- a/libc/xtensa-lx106-elf/include/sys/config.h +++ b/libc/xtensa-lx106-elf/include/sys/config.h @@ -75,7 +75,7 @@ #define _POINTER_INT short #endif -#if defined(__m68k__) || defined(__mc68000__) +#if defined(__m68k__) || defined(__mc68000__) || defined(__riscv) #define _READ_WRITE_RETURN_TYPE _ssize_t #endif @@ -92,7 +92,6 @@ /* we want the reentrancy structure to be returned by a function */ #define __DYNAMIC_REENT__ #define HAVE_GETDATE -#define _HAVE_SYSTYPES #define _READ_WRITE_RETURN_TYPE _ssize_t #define __LARGE64_FILES 1 /* we use some glibc header files so turn on glibc large file feature */ @@ -155,6 +154,7 @@ #define _REENT_SMALL #endif +#define __BUFSIZ__ 256 #define __SMALL_BITFIELDS #ifdef __MSP430X_LARGE__ @@ -185,6 +185,10 @@ #define __CUSTOM_FILE_IO__ #endif +#if defined(__or1k__) || defined(__or1knd__) +#define __DYNAMIC_REENT__ +#endif + #ifdef __XTENSA__ #include #define MALLOC_ALIGNMENT ((XCHAL_DATA_WIDTH) < 16 ? 16 : (XCHAL_DATA_WIDTH)) @@ -235,9 +239,6 @@ #if defined(__CYGWIN__) #include -#if !defined (__STRICT_ANSI__) || (__STDC_VERSION__ >= 199901L) -#define __USE_XOPEN2K 1 -#endif #endif #if defined(__rtems__) @@ -245,6 +246,7 @@ #define _READ_WRITE_RETURN_TYPE _ssize_t #define __DYNAMIC_REENT__ #define _REENT_GLOBAL_ATEXIT +#define _REENT_GLOBAL_STDIO_STREAMS #endif #ifndef __EXPORT @@ -282,6 +284,18 @@ #endif #endif +#ifdef _WANT_REENT_GLOBAL_STDIO_STREAMS +#ifndef _REENT_GLOBAL_STDIO_STREAMS +#define _REENT_GLOBAL_STDIO_STREAMS +#endif +#endif + +#ifdef _WANT_USE_LONG_TIME_T +#ifndef _USE_LONG_TIME_T +#define _USE_LONG_TIME_T +#endif +#endif + /* If _MB_EXTENDED_CHARSETS_ALL is set, we want all of the extended charsets. The extended charsets add a few functions and a couple of tables of a few K each. */ diff --git a/libc/xtensa-lx106-elf/include/sys/features.h b/libc/xtensa-lx106-elf/include/sys/features.h index 1d90921..c9133af 100644 --- a/libc/xtensa-lx106-elf/include/sys/features.h +++ b/libc/xtensa-lx106-elf/include/sys/features.h @@ -1,7 +1,7 @@ /* * Written by Joel Sherrill . * - * COPYRIGHT (c) 1989-2000. + * COPYRIGHT (c) 1989-2014. * * On-Line Applications Research Corporation (OAR). * @@ -25,11 +25,7 @@ extern "C" { #endif -/* Macros to determine that newlib is being used. Put in this header to - * be similar to where glibc stores its version of these macros. - */ -#define __NEWLIB__ 2 -#define __NEWLIB_MINOR__ 1 +#include <_newlib_version.h> /* Macro to test version of GCC. Returns 0 for non-GCC or too old GCC. */ #ifndef __GNUC_PREREQ @@ -43,6 +39,281 @@ extern "C" { /* Version with trailing underscores for BSD compatibility. */ #define __GNUC_PREREQ__(ma, mi) __GNUC_PREREQ(ma, mi) + +/* + * Feature test macros control which symbols are exposed by the system + * headers. Any of these must be defined before including any headers. + * + * __STRICT_ANSI__ (defined by gcc -ansi, -std=c90, -std=c99, or -std=c11) + * ISO C + * + * _POSIX_SOURCE (deprecated by _POSIX_C_SOURCE=1) + * _POSIX_C_SOURCE >= 1 + * POSIX.1-1990 + * + * _POSIX_C_SOURCE >= 2 + * POSIX.2-1992 + * + * _POSIX_C_SOURCE >= 199309L + * POSIX.1b-1993 Real-time extensions + * + * _POSIX_C_SOURCE >= 199506L + * POSIX.1c-1995 Threads extensions + * + * _POSIX_C_SOURCE >= 200112L + * POSIX.1-2001 and C99 + * + * _POSIX_C_SOURCE >= 200809L + * POSIX.1-2008 + * + * _XOPEN_SOURCE + * POSIX.1-1990 and XPG4 + * + * _XOPEN_SOURCE_EXTENDED + * SUSv1 (POSIX.2-1992 plus XPG4v2) + * + * _XOPEN_SOURCE >= 500 + * SUSv2 (POSIX.1c-1995 plus XSI) + * + * _XOPEN_SOURCE >= 600 + * SUSv3 (POSIX.1-2001 plus XSI) and C99 + * + * _XOPEN_SOURCE >= 700 + * SUSv4 (POSIX.1-2008 plus XSI) + * + * _ISOC99_SOURCE or gcc -std=c99 or g++ + * ISO C99 + * + * _ISOC11_SOURCE or gcc -std=c11 or g++ -std=c++11 + * ISO C11 + * + * _ATFILE_SOURCE (implied by _POSIX_C_SOURCE >= 200809L) + * "at" functions + * + * _LARGEFILE_SOURCE (deprecated by _XOPEN_SOURCE >= 500) + * fseeko, ftello + * + * _GNU_SOURCE + * All of the above plus GNU extensions + * + * _BSD_SOURCE (deprecated by _DEFAULT_SOURCE) + * _SVID_SOURCE (deprecated by _DEFAULT_SOURCE) + * _DEFAULT_SOURCE (or none of the above) + * POSIX-1.2008 with BSD and SVr4 extensions + */ + +#ifdef _GNU_SOURCE +#undef _ATFILE_SOURCE +#define _ATFILE_SOURCE 1 +#undef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#undef _ISOC99_SOURCE +#define _ISOC99_SOURCE 1 +#undef _ISOC11_SOURCE +#define _ISOC11_SOURCE 1 +#undef _POSIX_SOURCE +#define _POSIX_SOURCE 1 +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#undef _XOPEN_SOURCE +#define _XOPEN_SOURCE 700 +#undef _XOPEN_SOURCE_EXTENDED +#define _XOPEN_SOURCE_EXTENDED 1 +#endif /* _GNU_SOURCE */ + +#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || \ + (!defined(__STRICT_ANSI__) && !defined(_ANSI_SOURCE) && \ + !defined(_ISOC99_SOURCE) && !defined(_POSIX_SOURCE) && \ + !defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) +#undef _DEFAULT_SOURCE +#define _DEFAULT_SOURCE 1 +#endif + +#if defined(_DEFAULT_SOURCE) +#undef _POSIX_SOURCE +#define _POSIX_SOURCE 1 +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + +#if !defined(_POSIX_SOURCE) && !defined(_POSIX_C_SOURCE) && \ + ((!defined(__STRICT_ANSI__) && !defined(_ANSI_SOURCE)) || \ + (_XOPEN_SOURCE - 0) >= 500) +#define _POSIX_SOURCE 1 +#if !defined(_XOPEN_SOURCE) || (_XOPEN_SOURCE - 0) >= 700 +#define _POSIX_C_SOURCE 200809L +#elif (_XOPEN_SOURCE - 0) >= 600 +#define _POSIX_C_SOURCE 200112L +#elif (_XOPEN_SOURCE - 0) >= 500 +#define _POSIX_C_SOURCE 199506L +#elif (_XOPEN_SOURCE - 0) < 500 +#define _POSIX_C_SOURCE 2 +#endif +#endif + +#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200809 +#undef _ATFILE_SOURCE +#define _ATFILE_SOURCE 1 +#endif + +/* + * The following private macros are used throughout the headers to control + * which symbols should be exposed. They are for internal use only, as + * indicated by the leading double underscore, and must never be used outside + * of these headers. + * + * __POSIX_VISIBLE + * any version of POSIX.1; enabled by default, or with _POSIX_SOURCE, + * any value of _POSIX_C_SOURCE, or _XOPEN_SOURCE >= 500. + * + * __POSIX_VISIBLE >= 2 + * POSIX.2-1992; enabled by default, with _POSIX_C_SOURCE >= 2, + * or _XOPEN_SOURCE >= 500. + * + * __POSIX_VISIBLE >= 199309 + * POSIX.1b-1993; enabled by default, with _POSIX_C_SOURCE >= 199309L, + * or _XOPEN_SOURCE >= 500. + * + * __POSIX_VISIBLE >= 199506 + * POSIX.1c-1995; enabled by default, with _POSIX_C_SOURCE >= 199506L, + * or _XOPEN_SOURCE >= 500. + * + * __POSIX_VISIBLE >= 200112 + * POSIX.1-2001; enabled by default, with _POSIX_C_SOURCE >= 200112L, + * or _XOPEN_SOURCE >= 600. + * + * __POSIX_VISIBLE >= 200809 + * POSIX.1-2008; enabled by default, with _POSIX_C_SOURCE >= 200809L, + * or _XOPEN_SOURCE >= 700. + * + * __XSI_VISIBLE + * XPG4 XSI extensions; enabled with any version of _XOPEN_SOURCE. + * + * __XSI_VISIBLE >= 4 + * SUSv1 XSI extensions; enabled with both _XOPEN_SOURCE and + * _XOPEN_SOURCE_EXTENDED together. + * + * __XSI_VISIBLE >= 500 + * SUSv2 XSI extensions; enabled with _XOPEN_SOURCE >= 500. + * + * __XSI_VISIBLE >= 600 + * SUSv3 XSI extensions; enabled with _XOPEN_SOURCE >= 600. + * + * __XSI_VISIBLE >= 700 + * SUSv4 XSI extensions; enabled with _XOPEN_SOURCE >= 700. + * + * __ISO_C_VISIBLE >= 1999 + * ISO C99; enabled with gcc -std=c99 or newer (on by default since GCC 5), + * any version of C++, or with _ISOC99_SOURCE, _POSIX_C_SOURCE >= 200112L, + * or _XOPEN_SOURCE >= 600. + * + * __ISO_C_VISIBLE >= 2011 + * ISO C11; enabled with gcc -std=c11 or newer (on by default since GCC 5), + * g++ -std=c++11 or newer (on by default since GCC 6), or with + * _ISOC11_SOURCE. + * + * __ATFILE_VISIBLE + * "at" functions; enabled by default, with _ATFILE_SOURCE, + * _POSIX_C_SOURCE >= 200809L, or _XOPEN_SOURCE >= 700. + * + * __LARGEFILE_VISIBLE + * fseeko, ftello; enabled with _LARGEFILE_SOURCE or _XOPEN_SOURCE >= 500. + * + * __BSD_VISIBLE + * BSD extensions; enabled by default, or with _BSD_SOURCE. + * + * __SVID_VISIBLE + * SVr4 extensions; enabled by default, or with _SVID_SOURCE. + * + * __MISC_VISIBLE + * Extensions found in both BSD and SVr4 (shorthand for + * (__BSD_VISIBLE || __SVID_VISIBLE)), or newlib-specific + * extensions; enabled by default. + * + * __GNU_VISIBLE + * GNU extensions; enabled with _GNU_SOURCE. + * + * In all cases above, "enabled by default" means either by defining + * _DEFAULT_SOURCE, or by not defining any of the public feature test macros. + * Defining _GNU_SOURCE makes all of the above avaliable. + */ + +#ifdef _ATFILE_SOURCE +#define __ATFILE_VISIBLE 1 +#else +#define __ATFILE_VISIBLE 0 +#endif + +#ifdef _DEFAULT_SOURCE +#define __BSD_VISIBLE 1 +#else +#define __BSD_VISIBLE 0 +#endif + +#ifdef _GNU_SOURCE +#define __GNU_VISIBLE 1 +#else +#define __GNU_VISIBLE 0 +#endif + +#if defined(_ISOC11_SOURCE) || \ + (__STDC_VERSION__ - 0) >= 201112L || (__cplusplus - 0) >= 201103L +#define __ISO_C_VISIBLE 2011 +#elif defined(_ISOC99_SOURCE) || (_POSIX_C_SOURCE - 0) >= 200112L || \ + (__STDC_VERSION__ - 0) >= 199901L || defined(__cplusplus) +#define __ISO_C_VISIBLE 1999 +#else +#define __ISO_C_VISIBLE 1990 +#endif + +#if defined(_LARGEFILE_SOURCE) || (_XOPEN_SOURCE - 0) >= 500 +#define __LARGEFILE_VISIBLE 1 +#else +#define __LARGEFILE_VISIBLE 0 +#endif + +#ifdef _DEFAULT_SOURCE +#define __MISC_VISIBLE 1 +#else +#define __MISC_VISIBLE 0 +#endif + +#if (_POSIX_C_SOURCE - 0) >= 200809L +#define __POSIX_VISIBLE 200809 +#elif (_POSIX_C_SOURCE - 0) >= 200112L +#define __POSIX_VISIBLE 200112 +#elif (_POSIX_C_SOURCE - 0) >= 199506L +#define __POSIX_VISIBLE 199506 +#elif (_POSIX_C_SOURCE - 0) >= 199309L +#define __POSIX_VISIBLE 199309 +#elif (_POSIX_C_SOURCE - 0) >= 2 || defined(_XOPEN_SOURCE) +#define __POSIX_VISIBLE 199209 +#elif defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) +#define __POSIX_VISIBLE 199009 +#else +#define __POSIX_VISIBLE 0 +#endif + +#ifdef _DEFAULT_SOURCE +#define __SVID_VISIBLE 1 +#else +#define __SVID_VISIBLE 0 +#endif + +#if (_XOPEN_SOURCE - 0) >= 700 +#define __XSI_VISIBLE 700 +#elif (_XOPEN_SOURCE - 0) >= 600 +#define __XSI_VISIBLE 600 +#elif (_XOPEN_SOURCE - 0) >= 500 +#define __XSI_VISIBLE 500 +#elif defined(_XOPEN_SOURCE) && defined(_XOPEN_SOURCE_EXTENDED) +#define __XSI_VISIBLE 4 +#elif defined(_XOPEN_SOURCE) +#define __XSI_VISIBLE 1 +#else +#define __XSI_VISIBLE 0 +#endif + /* RTEMS adheres to POSIX -- 1003.1b with some features from annexes. */ #ifdef __rtems__ @@ -57,11 +328,12 @@ extern "C" { #define _POSIX_MEMORY_PROTECTION 1 #define _POSIX_MESSAGE_PASSING 1 #define _POSIX_MONOTONIC_CLOCK 200112L +#define _POSIX_CLOCK_SELECTION 200112L #define _POSIX_PRIORITIZED_IO 1 #define _POSIX_PRIORITY_SCHEDULING 1 #define _POSIX_REALTIME_SIGNALS 1 #define _POSIX_SEMAPHORES 1 -/* #define _POSIX_SHARED_MEMORY_OBJECTS 1 */ +#define _POSIX_SHARED_MEMORY_OBJECTS 1 #define _POSIX_SYNCHRONIZED_IO 1 #define _POSIX_TIMERS 1 #define _POSIX_BARRIERS 200112L @@ -94,6 +366,9 @@ extern "C" { /* UNIX98 added some new pthread mutex attributes */ #define _UNIX98_THREAD_MUTEX_ATTRIBUTES 1 +/* POSIX 1003.26-2003 defined device control method */ +#define _POSIX_26_VERSION 200312L + #endif /* XMK loosely adheres to POSIX -- 1003.1 */ @@ -111,62 +386,82 @@ extern "C" { #ifdef __CYGWIN__ -#if !defined(__STRICT_ANSI__) || defined(__cplusplus) || __STDC_VERSION__ >= 199901L +#if __POSIX_VISIBLE >= 200809 +#define _POSIX_VERSION 200809L +#define _POSIX2_VERSION 200809L +#elif __POSIX_VISIBLE >= 200112 #define _POSIX_VERSION 200112L #define _POSIX2_VERSION 200112L -#define _XOPEN_VERSION 600 +#elif __POSIX_VISIBLE >= 199506 +#define _POSIX_VERSION 199506L +#define _POSIX2_VERSION 199506L +#elif __POSIX_VISIBLE >= 199309 +#define _POSIX_VERSION 199309L +#define _POSIX2_VERSION 199209L +#elif __POSIX_VISIBLE >= 199209 +#define _POSIX_VERSION 199009L +#define _POSIX2_VERSION 199209L +#elif __POSIX_VISIBLE +#define _POSIX_VERSION 199009L +#endif +#if __XSI_VISIBLE >= 4 +#define _XOPEN_VERSION __XSI_VISIBLE +#endif -#define _POSIX_ADVISORY_INFO 200112L +#define _POSIX_ADVISORY_INFO 200809L /* #define _POSIX_ASYNCHRONOUS_IO -1 */ -/* #define _POSIX_BARRIERS -1 */ +#define _POSIX_BARRIERS 200809L #define _POSIX_CHOWN_RESTRICTED 1 -#define _POSIX_CLOCK_SELECTION 200112L -#define _POSIX_CPUTIME 200112L -#define _POSIX_FSYNC 200112L -#define _POSIX_IPV6 200112L +#define _POSIX_CLOCK_SELECTION 200809L +#define _POSIX_CPUTIME 200809L +#define _POSIX_FSYNC 200809L +#define _POSIX_IPV6 200809L #define _POSIX_JOB_CONTROL 1 -#define _POSIX_MAPPED_FILES 200112L +#define _POSIX_MAPPED_FILES 200809L /* #define _POSIX_MEMLOCK -1 */ -#define _POSIX_MEMLOCK_RANGE 200112L -#define _POSIX_MEMORY_PROTECTION 200112L -#define _POSIX_MESSAGE_PASSING 200112L -#define _POSIX_MONOTONIC_CLOCK 200112L +#define _POSIX_MEMLOCK_RANGE 200809L +#define _POSIX_MEMORY_PROTECTION 200809L +#define _POSIX_MESSAGE_PASSING 200809L +#define _POSIX_MONOTONIC_CLOCK 200809L #define _POSIX_NO_TRUNC 1 /* #define _POSIX_PRIORITIZED_IO -1 */ -#define _POSIX_PRIORITY_SCHEDULING 200112L -#define _POSIX_RAW_SOCKETS 200112L -#define _POSIX_READER_WRITER_LOCKS 200112L -#define _POSIX_REALTIME_SIGNALS 200112L +#define _POSIX_PRIORITY_SCHEDULING 200809L +#define _POSIX_RAW_SOCKETS 200809L +#define _POSIX_READER_WRITER_LOCKS 200809L +#define _POSIX_REALTIME_SIGNALS 200809L #define _POSIX_REGEXP 1 #define _POSIX_SAVED_IDS 1 -#define _POSIX_SEMAPHORES 200112L -#define _POSIX_SHARED_MEMORY_OBJECTS 200112L +#define _POSIX_SEMAPHORES 200809L +#define _POSIX_SHARED_MEMORY_OBJECTS 200809L #define _POSIX_SHELL 1 -/* #define _POSIX_SPAWN -1 */ -#define _POSIX_SPIN_LOCKS 200112L +#define _POSIX_SPAWN 200809L +#define _POSIX_SPIN_LOCKS 200809L /* #define _POSIX_SPORADIC_SERVER -1 */ -#define _POSIX_SYNCHRONIZED_IO 200112L -#define _POSIX_THREAD_ATTR_STACKADDR 200112L -#define _POSIX_THREAD_ATTR_STACKSIZE 200112L -#define _POSIX_THREAD_CPUTIME 200112L +#define _POSIX_SYNCHRONIZED_IO 200809L +#define _POSIX_THREAD_ATTR_STACKADDR 200809L +#define _POSIX_THREAD_ATTR_STACKSIZE 200809L +#define _POSIX_THREAD_CPUTIME 200809L /* #define _POSIX_THREAD_PRIO_INHERIT -1 */ /* #define _POSIX_THREAD_PRIO_PROTECT -1 */ -#define _POSIX_THREAD_PRIORITY_SCHEDULING 200112L -#define _POSIX_THREAD_PROCESS_SHARED 200112L -#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L +#define _POSIX_THREAD_PRIORITY_SCHEDULING 200809L +#define _POSIX_THREAD_PROCESS_SHARED 200809L +#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L /* #define _POSIX_THREAD_SPORADIC_SERVER -1 */ -#define _POSIX_THREADS 200112L +#define _POSIX_THREADS 200809L /* #define _POSIX_TIMEOUTS -1 */ -#define _POSIX_TIMERS 1 +#define _POSIX_TIMERS 200809L /* #define _POSIX_TRACE -1 */ /* #define _POSIX_TRACE_EVENT_FILTER -1 */ /* #define _POSIX_TRACE_INHERIT -1 */ /* #define _POSIX_TRACE_LOG -1 */ /* #define _POSIX_TYPED_MEMORY_OBJECTS -1 */ #define _POSIX_VDISABLE '\0' -#define _POSIX2_C_BIND 200112L -#define _POSIX2_C_DEV 200112L -#define _POSIX2_CHAR_TERM 200112L + +#if __POSIX_VISIBLE >= 2 +#define _POSIX2_C_VERSION _POSIX2_VERSION +#define _POSIX2_C_BIND _POSIX2_VERSION +#define _POSIX2_C_DEV _POSIX2_VERSION +#define _POSIX2_CHAR_TERM _POSIX2_VERSION /* #define _POSIX2_FORT_DEV -1 */ /* #define _POSIX2_FORT_RUN -1 */ /* #define _POSIX2_LOCALEDEF -1 */ @@ -176,8 +471,10 @@ extern "C" { /* #define _POSIX2_PBS_LOCATE -1 */ /* #define _POSIX2_PBS_MESSAGE -1 */ /* #define _POSIX2_PBS_TRACK -1 */ -#define _POSIX2_SW_DEV 200112L -#define _POSIX2_UPE 200112L +#define _POSIX2_SW_DEV _POSIX2_VERSION +#define _POSIX2_UPE _POSIX2_VERSION +#endif /* __POSIX_VISIBLE >= 2 */ + #define _POSIX_V6_ILP32_OFF32 -1 #ifdef __LP64__ #define _POSIX_V6_ILP32_OFFBIG -1 @@ -188,10 +485,16 @@ extern "C" { #define _POSIX_V6_LP64_OFF64 -1 #define _POSIX_V6_LPBIG_OFFBIG -1 #endif +#define _POSIX_V7_ILP32_OFF32 _POSIX_V6_ILP32_OFF32 +#define _POSIX_V7_ILP32_OFFBIG _POSIX_V6_ILP32_OFFBIG +#define _POSIX_V7_LP64_OFF64 _POSIX_V6_LP64_OFF64 +#define _POSIX_V7_LPBIG_OFFBIG _POSIX_V6_LPBIG_OFFBIG #define _XBS5_ILP32_OFF32 _POSIX_V6_ILP32_OFF32 #define _XBS5_ILP32_OFFBIG _POSIX_V6_ILP32_OFFBIG #define _XBS5_LP64_OFF64 _POSIX_V6_LP64_OFF64 #define _XBS5_LPBIG_OFFBIG _POSIX_V6_LPBIG_OFFBIG + +#if __XSI_VISIBLE #define _XOPEN_CRYPT 1 #define _XOPEN_ENH_I18N 1 /* #define _XOPEN_LEGACY -1 */ @@ -200,35 +503,14 @@ extern "C" { #define _XOPEN_SHM 1 /* #define _XOPEN_STREAMS -1 */ /* #define _XOPEN_UNIX -1 */ +#endif /* __XSI_VISIBLE */ -#endif /* !__STRICT_ANSI__ || __cplusplus || __STDC_VERSION__ >= 199901L */ - -/* The value corresponds to UNICODE version 4.0, which is the version - supported by XP. Newlib supports 5.2 (2011) but so far Cygwin needs - the MS conversions for double-byte charsets. */ -#define __STDC_ISO_10646__ 200305L +/* The value corresponds to UNICODE version 5.2, which is the current + state of newlib's wide char conversion functions. */ +#define __STDC_ISO_10646__ 200910L #endif /* __CYGWIN__ */ -/* Per the permission given in POSIX.1-2008 section 2.2.1, define - * _POSIX_C_SOURCE if _XOPEN_SOURCE is defined and _POSIX_C_SOURCE is not. - * (_XOPEN_SOURCE indicates that XSI extensions are desired by an application.) - * This permission is first granted in 2008, but use it for older ones, also. - * Allow for _XOPEN_SOURCE to be empty (from the earliest form of it, before it - * was required to have specific values). - */ -#if !defined(_POSIX_C_SOURCE) && defined(_XOPEN_SOURCE) - #if (_XOPEN_SOURCE - 0) == 700 /* POSIX.1-2008 */ - #define _POSIX_C_SOURCE 200809L - #elif (_XOPEN_SOURCE - 0) == 600 /* POSIX.1-2001 or 2004 */ - #define _POSIX_C_SOURCE 200112L - #elif (_XOPEN_SOURCE - 0) == 500 /* POSIX.1-1995 */ - #define _POSIX_C_SOURCE 199506L - #elif (_XOPEN_SOURCE - 0) < 500 /* really old */ - #define _POSIX_C_SOURCE 2 - #endif -#endif - #ifdef __cplusplus } #endif diff --git a/libc/xtensa-lx106-elf/include/sys/param.h b/libc/xtensa-lx106-elf/include/sys/param.h index ef203d3..9a6f115 100644 --- a/libc/xtensa-lx106-elf/include/sys/param.h +++ b/libc/xtensa-lx106-elf/include/sys/param.h @@ -10,6 +10,9 @@ #include #include +#ifndef NBBY +# define NBBY 8 /* number of bits in a byte */ +#endif #ifndef HZ # define HZ (60) #endif @@ -25,4 +28,8 @@ #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) < (b) ? (a) : (b)) +#ifndef howmany +#define howmany(x, y) (((x)+((y)-1))/(y)) +#endif + #endif diff --git a/libc/xtensa-lx106-elf/include/sys/queue.h b/libc/xtensa-lx106-elf/include/sys/queue.h index 4bc7dac..491bdde 100644 --- a/libc/xtensa-lx106-elf/include/sys/queue.h +++ b/libc/xtensa-lx106-elf/include/sys/queue.h @@ -10,7 +10,7 @@ * 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. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -76,11 +76,17 @@ * * For details on the use of these macros, see the queue(3) manual page. * + * Below is a summary of implemented functions where: + * + means the macro is available + * - means the macro is not available + * s means the macro is available but is slow (runs in O(n) time) * * SLIST LIST STAILQ TAILQ * _HEAD + + + + + * _CLASS_HEAD + + + + * _HEAD_INITIALIZER + + + + * _ENTRY + + + + + * _CLASS_ENTRY + + + + * _INIT + + + + * _EMPTY + + + + * _FIRST + + + + @@ -88,21 +94,31 @@ * _PREV - + - + * _LAST - - + + * _FOREACH + + + + + * _FOREACH_FROM + + + + * _FOREACH_SAFE + + + + + * _FOREACH_FROM_SAFE + + + + * _FOREACH_REVERSE - - - + + * _FOREACH_REVERSE_FROM - - - + * _FOREACH_REVERSE_SAFE - - - + + * _FOREACH_REVERSE_FROM_SAFE - - - + * _INSERT_HEAD + + + + * _INSERT_BEFORE - + - + * _INSERT_AFTER + + + + * _INSERT_TAIL - - + + - * _CONCAT - - + + + * _CONCAT s s + + * _REMOVE_AFTER + - + - * _REMOVE_HEAD + - + - - * _REMOVE + + + + + * _REMOVE s + s + * _SWAP + + + + * */ #ifdef QUEUE_MACRO_DEBUG +#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH +#define QUEUE_MACRO_DEBUG_TRACE +#define QUEUE_MACRO_DEBUG_TRASH +#endif + +#ifdef QUEUE_MACRO_DEBUG_TRACE /* Store the last 2 places the queue element or head was altered */ struct qm_trace { unsigned long lastline; @@ -112,9 +128,7 @@ struct qm_trace { }; #define TRACEBUF struct qm_trace trace; -#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } , -#define TRASHIT(x) do {(x) = (void *)-1;} while (0) -#define QMD_SAVELINK(name, link) void **name = (void *)&(link) +#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } , #define QMD_TRACE_HEAD(head) do { \ (head)->trace.prevline = (head)->trace.lastline; \ @@ -130,14 +144,35 @@ struct qm_trace { (elem)->trace.lastfile = __FILE__; \ } while (0) -#else +#else /* !QUEUE_MACRO_DEBUG_TRACE */ #define QMD_TRACE_ELEM(elem) #define QMD_TRACE_HEAD(head) -#define QMD_SAVELINK(name, link) #define TRACEBUF #define TRACEBUF_INITIALIZER +#endif /* QUEUE_MACRO_DEBUG_TRACE */ + +#ifdef QUEUE_MACRO_DEBUG_TRASH +#define TRASHIT(x) do {(x) = (void *)-1;} while (0) +#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1) +#else /* !QUEUE_MACRO_DEBUG_TRASH */ #define TRASHIT(x) -#endif /* QUEUE_MACRO_DEBUG */ +#define QMD_IS_TRASHED(x) 0 +#endif /* QUEUE_MACRO_DEBUG_TRASH */ + +#if defined(QUEUE_MACRO_DEBUG_TRACE) || defined(QUEUE_MACRO_DEBUG_TRASH) +#define QMD_SAVELINK(name, link) void **name = (void *)&(link) +#else /* !QUEUE_MACRO_DEBUG_TRACE && !QUEUE_MACRO_DEBUG_TRASH */ +#define QMD_SAVELINK(name, link) +#endif /* QUEUE_MACRO_DEBUG_TRACE || QUEUE_MACRO_DEBUG_TRASH */ + +#ifdef __cplusplus +/* + * In C++ there can be structure lists and class lists: + */ +#define QUEUE_TYPEOF(type) type +#else +#define QUEUE_TYPEOF(type) struct type +#endif /* * Singly-linked List declarations. @@ -147,6 +182,11 @@ struct name { \ struct type *slh_first; /* first element */ \ } +#define SLIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *slh_first; /* first element */ \ +} + #define SLIST_HEAD_INITIALIZER(head) \ { NULL } @@ -155,9 +195,37 @@ struct { \ struct type *sle_next; /* next element */ \ } +#define SLIST_CLASS_ENTRY(type) \ +struct { \ + class type *sle_next; /* next element */ \ +} + /* * Singly-linked List functions. */ +#if (defined(_KERNEL) && defined(INVARIANTS)) +#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \ + if (*(prevp) != (elm)) \ + panic("Bad prevptr *(%p) == %p != %p", \ + (prevp), *(prevp), (elm)); \ +} while (0) +#else +#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) +#endif + +#define SLIST_CONCAT(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \ + if (curelm == NULL) { \ + if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \ + SLIST_INIT(head2); \ + } else if (SLIST_FIRST(head2) != NULL) { \ + while (SLIST_NEXT(curelm, field) != NULL) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \ + SLIST_INIT(head2); \ + } \ +} while (0) + #define SLIST_EMPTY(head) ((head)->slh_first == NULL) #define SLIST_FIRST(head) ((head)->slh_first) @@ -167,11 +235,21 @@ struct { \ (var); \ (var) = SLIST_NEXT((var), field)) +#define SLIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = SLIST_FIRST((head)); \ (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ (var) = (tvar)) +#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \ + (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ for ((varp) = &SLIST_FIRST((head)); \ ((var) = *(varp)) != NULL; \ @@ -199,7 +277,7 @@ struct { \ SLIST_REMOVE_HEAD((head), field); \ } \ else { \ - struct type *curelm = SLIST_FIRST((head)); \ + QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \ while (SLIST_NEXT(curelm, field) != (elm)) \ curelm = SLIST_NEXT(curelm, field); \ SLIST_REMOVE_AFTER(curelm, field); \ @@ -216,8 +294,14 @@ struct { \ SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ } while (0) +#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \ + QMD_SLIST_CHECK_PREVPTR(prevp, elm); \ + *(prevp) = SLIST_NEXT(elm, field); \ + TRASHIT((elm)->field.sle_next); \ +} while (0) + #define SLIST_SWAP(head1, head2, type) do { \ - struct type *swap_first = SLIST_FIRST(head1); \ + QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \ SLIST_FIRST(head1) = SLIST_FIRST(head2); \ SLIST_FIRST(head2) = swap_first; \ } while (0) @@ -231,6 +315,12 @@ struct name { \ struct type **stqh_last;/* addr of last next element */ \ } +#define STAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *stqh_first; /* first element */ \ + class type **stqh_last; /* addr of last next element */ \ +} + #define STAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).stqh_first } @@ -239,6 +329,11 @@ struct { \ struct type *stqe_next; /* next element */ \ } +#define STAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *stqe_next; /* next element */ \ +} + /* * Singly-linked Tail queue functions. */ @@ -259,12 +354,21 @@ struct { \ (var); \ (var) = STAILQ_NEXT((var), field)) +#define STAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = STAILQ_FIRST((head)); \ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ (var) = (tvar)) +#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + #define STAILQ_INIT(head) do { \ STAILQ_FIRST((head)) = NULL; \ (head)->stqh_last = &STAILQ_FIRST((head)); \ @@ -288,9 +392,10 @@ struct { \ (head)->stqh_last = &STAILQ_NEXT((elm), field); \ } while (0) -#define STAILQ_LAST(head, type, field) \ - (STAILQ_EMPTY((head)) ? NULL : \ - __containerof((head)->stqh_last, struct type, field.stqe_next)) +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? NULL : \ + __containerof((head)->stqh_last, \ + QUEUE_TYPEOF(type), field.stqe_next)) #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) @@ -300,7 +405,7 @@ struct { \ STAILQ_REMOVE_HEAD((head), field); \ } \ else { \ - struct type *curelm = STAILQ_FIRST((head)); \ + QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \ while (STAILQ_NEXT(curelm, field) != (elm)) \ curelm = STAILQ_NEXT(curelm, field); \ STAILQ_REMOVE_AFTER(head, curelm, field); \ @@ -326,8 +431,8 @@ struct { \ } while (0) #define STAILQ_SWAP(head1, head2, type) do { \ - struct type *swap_first = STAILQ_FIRST(head1); \ - struct type **swap_last = (head1)->stqh_last; \ + QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \ + QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \ STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \ (head1)->stqh_last = (head2)->stqh_last; \ STAILQ_FIRST(head2) = swap_first; \ @@ -347,6 +452,11 @@ struct name { \ struct type *lh_first; /* first element */ \ } +#define LIST_CLASS_HEAD(name, type) \ +struct name { \ + class type *lh_first; /* first element */ \ +} + #define LIST_HEAD_INITIALIZER(head) \ { NULL } @@ -356,11 +466,23 @@ struct { \ struct type **le_prev; /* address of previous next element */ \ } +#define LIST_CLASS_ENTRY(type) \ +struct { \ + class type *le_next; /* next element */ \ + class type **le_prev; /* address of previous next element */ \ +} + /* * List functions. */ #if (defined(_KERNEL) && defined(INVARIANTS)) +/* + * QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME) + * + * If the list is non-empty, validates that the first element of the list + * points back at 'head.' + */ #define QMD_LIST_CHECK_HEAD(head, field) do { \ if (LIST_FIRST((head)) != NULL && \ LIST_FIRST((head))->field.le_prev != \ @@ -368,6 +490,12 @@ struct { \ panic("Bad list head %p first->prev != head", (head)); \ } while (0) +/* + * QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME) + * + * If an element follows 'elm' in the list, validates that the next element + * points back at 'elm.' + */ #define QMD_LIST_CHECK_NEXT(elm, field) do { \ if (LIST_NEXT((elm), field) != NULL && \ LIST_NEXT((elm), field)->field.le_prev != \ @@ -375,6 +503,11 @@ struct { \ panic("Bad link elm %p next->prev != elm", (elm)); \ } while (0) +/* + * QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME) + * + * Validates that the previous element (or head of the list) points to 'elm.' + */ #define QMD_LIST_CHECK_PREV(elm, field) do { \ if (*(elm)->field.le_prev != (elm)) \ panic("Bad link elm %p prev->next != elm", (elm)); \ @@ -385,6 +518,23 @@ struct { \ #define QMD_LIST_CHECK_PREV(elm, field) #endif /* (_KERNEL && INVARIANTS) */ +#define LIST_CONCAT(head1, head2, type, field) do { \ + QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \ + if (curelm == NULL) { \ + if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \ + LIST_FIRST(head2)->field.le_prev = \ + &LIST_FIRST((head1)); \ + LIST_INIT(head2); \ + } \ + } else if (LIST_FIRST(head2) != NULL) { \ + while (LIST_NEXT(curelm, field) != NULL) \ + curelm = LIST_NEXT(curelm, field); \ + LIST_NEXT(curelm, field) = LIST_FIRST(head2); \ + LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \ + LIST_INIT(head2); \ + } \ +} while (0) + #define LIST_EMPTY(head) ((head)->lh_first == NULL) #define LIST_FIRST(head) ((head)->lh_first) @@ -394,11 +544,21 @@ struct { \ (var); \ (var) = LIST_NEXT((var), field)) +#define LIST_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var); \ + (var) = LIST_NEXT((var), field)) + #define LIST_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = LIST_FIRST((head)); \ (var) && ((tvar) = LIST_NEXT((var), field), 1); \ (var) = (tvar)) +#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : LIST_FIRST((head))); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + #define LIST_INIT(head) do { \ LIST_FIRST((head)) = NULL; \ } while (0) @@ -430,9 +590,10 @@ struct { \ #define LIST_NEXT(elm, field) ((elm)->field.le_next) -#define LIST_PREV(elm, head, type, field) \ - ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ - __containerof((elm)->field.le_prev, struct type, field.le_next)) +#define LIST_PREV(elm, head, type, field) \ + ((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \ + __containerof((elm)->field.le_prev, \ + QUEUE_TYPEOF(type), field.le_next)) #define LIST_REMOVE(elm, field) do { \ QMD_SAVELINK(oldnext, (elm)->field.le_next); \ @@ -448,7 +609,7 @@ struct { \ } while (0) #define LIST_SWAP(head1, head2, type, field) do { \ - struct type *swap_tmp = LIST_FIRST((head1)); \ + QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \ LIST_FIRST((head1)) = LIST_FIRST((head2)); \ LIST_FIRST((head2)) = swap_tmp; \ if ((swap_tmp = LIST_FIRST((head1))) != NULL) \ @@ -467,6 +628,13 @@ struct name { \ TRACEBUF \ } +#define TAILQ_CLASS_HEAD(name, type) \ +struct name { \ + class type *tqh_first; /* first element */ \ + class type **tqh_last; /* addr of last next element */ \ + TRACEBUF \ +} + #define TAILQ_HEAD_INITIALIZER(head) \ { NULL, &(head).tqh_first, TRACEBUF_INITIALIZER } @@ -477,10 +645,23 @@ struct { \ TRACEBUF \ } +#define TAILQ_CLASS_ENTRY(type) \ +struct { \ + class type *tqe_next; /* next element */ \ + class type **tqe_prev; /* address of previous next element */ \ + TRACEBUF \ +} + /* * Tail queue functions. */ #if (defined(_KERNEL) && defined(INVARIANTS)) +/* + * QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME) + * + * If the tailq is non-empty, validates that the first element of the tailq + * points back at 'head.' + */ #define QMD_TAILQ_CHECK_HEAD(head, field) do { \ if (!TAILQ_EMPTY(head) && \ TAILQ_FIRST((head))->field.tqe_prev != \ @@ -488,11 +669,22 @@ struct { \ panic("Bad tailq head %p first->prev != head", (head)); \ } while (0) +/* + * QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME) + * + * Validates that the tail of the tailq is a pointer to pointer to NULL. + */ #define QMD_TAILQ_CHECK_TAIL(head, field) do { \ if (*(head)->tqh_last != NULL) \ panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ } while (0) +/* + * QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME) + * + * If an element follows 'elm' in the tailq, validates that the next element + * points back at 'elm.' + */ #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ if (TAILQ_NEXT((elm), field) != NULL && \ TAILQ_NEXT((elm), field)->field.tqe_prev != \ @@ -500,6 +692,11 @@ struct { \ panic("Bad link elm %p next->prev != elm", (elm)); \ } while (0) +/* + * QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME) + * + * Validates that the previous element (or head of the tailq) points to 'elm.' + */ #define QMD_TAILQ_CHECK_PREV(elm, field) do { \ if (*(elm)->field.tqe_prev != (elm)) \ panic("Bad link elm %p prev->next != elm", (elm)); \ @@ -531,21 +728,41 @@ struct { \ (var); \ (var) = TAILQ_NEXT((var), field)) +#define TAILQ_FOREACH_FROM(var, head, field) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ for ((var) = TAILQ_FIRST((head)); \ (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ (var) = (tvar)) +#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ for ((var) = TAILQ_LAST((head), headname); \ (var); \ (var) = TAILQ_PREV((var), headname, field)) +#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ for ((var) = TAILQ_LAST((head), headname); \ (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ (var) = (tvar)) +#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \ + for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \ + (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ + (var) = (tvar)) + #define TAILQ_INIT(head) do { \ TAILQ_FIRST((head)) = NULL; \ (head)->tqh_last = &TAILQ_FIRST((head)); \ @@ -564,7 +781,7 @@ struct { \ TAILQ_NEXT((listelm), field) = (elm); \ (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ + QMD_TRACE_ELEM(&(listelm)->field); \ } while (0) #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ @@ -574,7 +791,7 @@ struct { \ *(listelm)->field.tqe_prev = (elm); \ (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ QMD_TRACE_ELEM(&(elm)->field); \ - QMD_TRACE_ELEM(&listelm->field); \ + QMD_TRACE_ELEM(&(listelm)->field); \ } while (0) #define TAILQ_INSERT_HEAD(head, elm, field) do { \ @@ -627,8 +844,8 @@ struct { \ } while (0) #define TAILQ_SWAP(head1, head2, type, field) do { \ - struct type *swap_first = (head1)->tqh_first; \ - struct type **swap_last = (head1)->tqh_last; \ + QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \ + QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \ (head1)->tqh_first = (head2)->tqh_first; \ (head1)->tqh_last = (head2)->tqh_last; \ (head2)->tqh_first = swap_first; \ diff --git a/libc/xtensa-lx106-elf/include/sys/reent.h b/libc/xtensa-lx106-elf/include/sys/reent.h index ce5b3ed..c045ca5 100644 --- a/libc/xtensa-lx106-elf/include/sys/reent.h +++ b/libc/xtensa-lx106-elf/include/sys/reent.h @@ -37,6 +37,8 @@ typedef __uint32_t __ULong; struct _reent; +struct __locale_t; + /* * If _REENT_SMALL is defined, we make struct _reent as small as possible, * by having nearly everything possible allocated at first use. @@ -384,8 +386,8 @@ struct _reent int __sdidinit; /* 1 means stdio has been init'd */ - int _current_category; /* unused */ - _CONST char *_current_locale; /* unused */ + int _unspecified_locale_info; /* unused, reserved for locale stuff */ + struct __locale_t *_locale;/* per-thread locale */ struct _mprec *_mp; @@ -429,7 +431,7 @@ extern const struct __sFILE_fake __sf_fake_stderr; _NULL, \ 0, \ 0, \ - "C", \ + _NULL, \ _NULL, \ _NULL, \ 0, \ @@ -446,16 +448,14 @@ extern const struct __sFILE_fake __sf_fake_stderr; _NULL \ } -#define _REENT_INIT_PTR(var) \ - { memset((var), 0, sizeof(*(var))); \ - (var)->_stdin = (__FILE *)&__sf_fake_stdin; \ +#define _REENT_INIT_PTR_ZEROED(var) \ + { (var)->_stdin = (__FILE *)&__sf_fake_stdin; \ (var)->_stdout = (__FILE *)&__sf_fake_stdout; \ (var)->_stderr = (__FILE *)&__sf_fake_stderr; \ - (var)->_current_locale = "C"; \ } -/* Only built the assert() calls if we are built with debugging. */ -#if DEBUG +/* Only add assert() calls if we are specified to debug. */ +#ifdef _REENT_CHECK_DEBUG #include #define __reent_assert(x) assert(x) #else @@ -578,8 +578,9 @@ struct _reent int _inc; /* used by tmpnam */ char _emergency[_REENT_EMERGENCY_SIZE]; - int _current_category; /* used by setlocale */ - _CONST char *_current_locale; + /* TODO */ + int _unspecified_locale_info; /* unused, reserved for locale stuff */ + struct __locale_t *_locale;/* per-thread locale */ int __sdidinit; /* 1 means stdio has been init'd */ @@ -643,18 +644,27 @@ struct _reent of the above members (on the off chance that future binary compatibility would be broken otherwise). */ struct _glue __sglue; /* root of glue chain */ +# ifndef _REENT_GLOBAL_STDIO_STREAMS __FILE __sf[3]; /* first three file descriptors */ +# endif }; +#ifdef _REENT_GLOBAL_STDIO_STREAMS +extern __FILE __sf[3]; +#define _REENT_STDIO_STREAM(var, index) &__sf[index] +#else +#define _REENT_STDIO_STREAM(var, index) &(var)->__sf[index] +#endif + #define _REENT_INIT(var) \ { 0, \ - &(var).__sf[0], \ - &(var).__sf[1], \ - &(var).__sf[2], \ + _REENT_STDIO_STREAM(&(var), 0), \ + _REENT_STDIO_STREAM(&(var), 1), \ + _REENT_STDIO_STREAM(&(var), 2), \ 0, \ "", \ 0, \ - "C", \ + _NULL, \ 0, \ _NULL, \ _NULL, \ @@ -694,12 +704,10 @@ struct _reent {_NULL, 0, _NULL} \ } -#define _REENT_INIT_PTR(var) \ - { memset((var), 0, sizeof(*(var))); \ - (var)->_stdin = &(var)->__sf[0]; \ - (var)->_stdout = &(var)->__sf[1]; \ - (var)->_stderr = &(var)->__sf[2]; \ - (var)->_current_locale = "C"; \ +#define _REENT_INIT_PTR_ZEROED(var) \ + { (var)->_stdin = _REENT_STDIO_STREAM(var, 0); \ + (var)->_stdout = _REENT_STDIO_STREAM(var, 1); \ + (var)->_stderr = _REENT_STDIO_STREAM(var, 2); \ (var)->_new._reent._rand_next = 1; \ (var)->_new._reent._r48._seed[0] = _RAND48_SEED_0; \ (var)->_new._reent._r48._seed[1] = _RAND48_SEED_1; \ @@ -745,6 +753,11 @@ struct _reent #endif /* !_REENT_SMALL */ +#define _REENT_INIT_PTR(var) \ + { memset((var), 0, sizeof(*(var))); \ + _REENT_INIT_PTR_ZEROED(var); \ + } + /* This value is used in stdlib/misc.c. reent/reent.c has to know it as well to make sure the freelist is correctly free'd. Therefore we define it here, rather than in stdlib/misc.c, as before. */ diff --git a/libc/xtensa-lx106-elf/include/sys/sched.h b/libc/xtensa-lx106-elf/include/sys/sched.h index 58f99d6..4adb6e2 100644 --- a/libc/xtensa-lx106-elf/include/sys/sched.h +++ b/libc/xtensa-lx106-elf/include/sys/sched.h @@ -21,6 +21,8 @@ #ifndef _SYS_SCHED_H_ #define _SYS_SCHED_H_ +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/libc/xtensa-lx106-elf/include/sys/select.h b/libc/xtensa-lx106-elf/include/sys/select.h new file mode 100644 index 0000000..f5dc586 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/select.h @@ -0,0 +1,87 @@ +/* select.h + Copyright 1998, 1999, 2000, 2001, 2005, 2009 Red Hat, Inc. + + Written by Geoffrey Noer + +This file is part of Cygwin. + +This software is a copyrighted work licensed under the terms of the +Cygwin license. Please consult the file "CYGWIN_LICENSE" for +details. */ + +#ifndef _SYS_SELECT_H +#define _SYS_SELECT_H + +/* We don't define fd_set and friends if we are compiling POSIX + source, or if we have included (or may include as indicated + by __USE_W32_SOCKETS) the W32api winsock[2].h header which + defines Windows versions of them. Note that a program which + includes the W32api winsock[2].h header must know what it is doing; + it must not call the Cygwin select function. +*/ +# if !(defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) + +#include +#include +#include +#include + +#if !defined(_SIGSET_T_DECLARED) +#define _SIGSET_T_DECLARED +typedef __sigset_t sigset_t; +#endif + +# define _SYS_TYPES_FD_SET +/* + * Select uses bit masks of file descriptors in longs. + * These macros manipulate such bit fields (the filesystem macros use chars). + * FD_SETSIZE may be defined by the user, but the default here + * should be >= NOFILE (param.h). + */ +# ifndef FD_SETSIZE +# define FD_SETSIZE 64 +# endif + +typedef unsigned long fd_mask; +# define NFDBITS (sizeof (fd_mask) * 8) /* bits per mask */ +# ifndef _howmany +# define _howmany(x,y) (((x)+((y)-1))/(y)) +# endif + +/* We use a macro for fd_set so that including Sockets.h afterwards + can work. */ +typedef struct _types_fd_set { + fd_mask fds_bits[_howmany(FD_SETSIZE, NFDBITS)]; +} _types_fd_set; + +#define fd_set _types_fd_set + +# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS))) +# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS))) +# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS))) +# define FD_ZERO(p) (__extension__ (void)({ \ + size_t __i; \ + char *__tmp = (char *)p; \ + for (__i = 0; __i < sizeof (*(p)); ++__i) \ + *__tmp++ = 0; \ +})) + +#if !defined (__INSIDE_CYGWIN_NET__) + +__BEGIN_DECLS + +int select __P ((int __n, fd_set *__readfds, fd_set *__writefds, + fd_set *__exceptfds, struct timeval *__timeout)); +#if __POSIX_VISIBLE >= 200112 +int pselect __P ((int __n, fd_set *__readfds, fd_set *__writefds, + fd_set *__exceptfds, const struct timespec *__timeout, + const sigset_t *__set)); +#endif + +__END_DECLS + +#endif /* !__INSIDE_CYGWIN_NET__ */ + +#endif /* !(_WINSOCK_H || _WINSOCKAPI_ || __USE_W32_SOCKETS) */ + +#endif /* sys/select.h */ diff --git a/libc/xtensa-lx106-elf/include/sys/signal.h b/libc/xtensa-lx106-elf/include/sys/signal.h index a29f525..ab35718 100644 --- a/libc/xtensa-lx106-elf/include/sys/signal.h +++ b/libc/xtensa-lx106-elf/include/sys/signal.h @@ -7,19 +7,22 @@ extern "C" { #endif #include "_ansi.h" +#include #include #include +#include +#include -/* #ifndef __STRICT_ANSI__*/ - -/* Cygwin defines it's own sigset_t in include/cygwin/signal.h */ -#ifndef __CYGWIN__ -typedef unsigned long sigset_t; +#if !defined(_SIGSET_T_DECLARED) +#define _SIGSET_T_DECLARED +typedef __sigset_t sigset_t; #endif -#if defined(__rtems__) +#if defined(__CYGWIN__) +#include +#else -#if defined(_POSIX_REALTIME_SIGNALS) +#if defined(_POSIX_REALTIME_SIGNALS) || __POSIX_VISIBLE >= 199309 /* sigev_notify values NOTE: P1003.1c/D10, p. 34 adds SIGEV_THREAD. */ @@ -67,14 +70,16 @@ typedef struct { int si_code; /* Cause of the signal */ union sigval si_value; /* Signal value */ } siginfo_t; -#endif +#endif /* defined(_POSIX_REALTIME_SIGNALS) || __POSIX_VISIBLE >= 199309 */ + +#if defined(__rtems__) /* 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 */ #define SA_NOCLDSTOP 0x1 /* Do not generate SIGCHLD when children stop */ #define SA_SIGINFO 0x2 /* Invoke the signal catching function with */ /* three arguments instead of one. */ -#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809 #define SA_ONSTACK 0x4 /* Signal delivery will be on a separate stack. */ #endif @@ -107,7 +112,22 @@ struct sigaction { #define sa_sigaction _signal_handlers._sigaction #endif -#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 +#else /* defined(__rtems__) */ + +#define SA_NOCLDSTOP 1 /* only value supported now for sa_flags */ + +typedef void (*_sig_func_ptr)(int); + +struct sigaction +{ + _sig_func_ptr sa_handler; + sigset_t sa_mask; + int sa_flags; +}; +#endif /* defined(__rtems__) */ +#endif /* defined(__CYGWIN__) */ + +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809 /* * Minimum and default signal stack constants. Allow for target overrides * from . @@ -125,6 +145,8 @@ struct sigaction { #define SS_ONSTACK 0x1 #define SS_DISABLE 0x2 +#endif + /* * Structure used in sigaltstack call. */ @@ -133,58 +155,33 @@ typedef struct sigaltstack { int ss_flags; /* Flags. */ size_t ss_size; /* Stack size. */ } stack_t; -#endif - -#elif defined(__CYGWIN__) -#include -#else -#define SA_NOCLDSTOP 1 /* only value supported now for sa_flags */ - -typedef void (*_sig_func_ptr)(int); - -struct sigaction -{ - _sig_func_ptr sa_handler; - sigset_t sa_mask; - int sa_flags; -}; -#endif /* defined(__rtems__) */ +#if __POSIX_VISIBLE #define SIG_SETMASK 0 /* set mask with sigprocmask() */ #define SIG_BLOCK 1 /* set of signals to block */ #define SIG_UNBLOCK 2 /* set of signals to, well, unblock */ -/* These depend upon the type of sigset_t, which right now - is always a long.. They're in the POSIX namespace, but - are not ANSI. */ -#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0) -#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0) -#define sigemptyset(what) (*(what) = 0, 0) -#define sigfillset(what) (*(what) = ~(0), 0) -#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0) - int _EXFUN(sigprocmask, (int how, const sigset_t *set, sigset_t *oset)); +#endif -#if defined(_POSIX_THREADS) +#if __POSIX_VISIBLE >= 199506 int _EXFUN(pthread_sigmask, (int how, const sigset_t *set, sigset_t *oset)); #endif #if defined(__CYGWIN__) || defined(__rtems__) -#undef sigaddset -#undef sigdelset -#undef sigemptyset -#undef sigfillset -#undef sigismember - #ifdef _COMPILING_NEWLIB int _EXFUN(_kill, (pid_t, int)); #endif /* _COMPILING_NEWLIB */ #endif /* __CYGWIN__ || __rtems__ */ -#if defined(__CYGWIN__) || defined(__rtems__) || defined(__SPU__) + +#if __POSIX_VISIBLE int _EXFUN(kill, (pid_t, int)); -#endif /* __CYGWIN__ || __rtems__ || __SPU__ */ -#if defined(__CYGWIN__) || defined(__rtems__) +#endif + +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 int _EXFUN(killpg, (pid_t, int)); +#endif +#if __POSIX_VISIBLE int _EXFUN(sigaction, (int, const struct sigaction *, struct sigaction *)); int _EXFUN(sigaddset, (sigset_t *, const int)); int _EXFUN(sigdelset, (sigset_t *, const int)); @@ -193,24 +190,45 @@ int _EXFUN(sigfillset, (sigset_t *)); int _EXFUN(sigemptyset, (sigset_t *)); int _EXFUN(sigpending, (sigset_t *)); int _EXFUN(sigsuspend, (const sigset_t *)); -int _EXFUN(sigpause, (int)); +int _EXFUN(sigwait, (const sigset_t *set, int *sig)); -#ifdef __rtems__ -#if __BSD_VISIBLE || __XSI_VISIBLE || __POSIX_VISIBLE >= 200112 +#if !defined(__CYGWIN__) && !defined(__rtems__) +/* These depend upon the type of sigset_t, which right now + is always a long.. They're in the POSIX namespace, but + are not ANSI. */ +#define sigaddset(what,sig) (*(what) |= (1<<(sig)), 0) +#define sigdelset(what,sig) (*(what) &= ~(1<<(sig)), 0) +#define sigemptyset(what) (*(what) = 0, 0) +#define sigfillset(what) (*(what) = ~(0), 0) +#define sigismember(what,sig) (((*(what)) & (1<<(sig))) != 0) +#endif /* !__CYGWIN__ && !__rtems__ */ +#endif /* __POSIX_VISIBLE */ + +/* There are two common sigpause variants, both of which take an int argument. + If you request _XOPEN_SOURCE or _GNU_SOURCE, you get the System V version, + which removes the given signal from the process's signal mask; otherwise + you get the BSD version, which sets the process's signal mask to the given + value. */ +#if __XSI_VISIBLE && !defined(__INSIDE_CYGWIN__) +# ifdef __GNUC__ +int _EXFUN(sigpause, (int)) __asm__ (__ASMNAME ("__xpg_sigpause")); +# else +int _EXFUN(__xpg_sigpause, (int)); +# define sigpause __xpg_sigpause +# endif +#elif __BSD_VISIBLE +int _EXFUN(sigpause, (int)); +#endif + +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809 int _EXFUN(sigaltstack, (const stack_t *__restrict, stack_t *__restrict)); #endif -#endif -#if defined(_POSIX_THREADS) -#ifdef __CYGWIN__ -# ifndef _CYGWIN_TYPES_H -# error You need the winsup sources or a cygwin installation to compile the cygwin version of newlib. -# endif -#endif +#if __POSIX_VISIBLE >= 199506 int _EXFUN(pthread_kill, (pthread_t thread, int sig)); #endif -#if defined(_POSIX_REALTIME_SIGNALS) +#if __POSIX_VISIBLE >= 199309 /* 3.3.8 Synchronously Accept a Signal, P1003.1b-1993, p. 76 NOTE: P1003.1c/D10, p. 39 adds sigwait(). */ @@ -219,16 +237,10 @@ int _EXFUN(sigwaitinfo, (const sigset_t *set, siginfo_t *info)); int _EXFUN(sigtimedwait, (const sigset_t *set, siginfo_t *info, const struct timespec *timeout) ); -int _EXFUN(sigwait, (const sigset_t *set, int *sig)); - /* 3.3.9 Queue a Signal to a Process, P1003.1b-1993, p. 78 */ int _EXFUN(sigqueue, (pid_t pid, int signo, const union sigval value)); -#endif /* defined(_POSIX_REALTIME_SIGNALS) */ - -#endif /* defined(__CYGWIN__) || defined(__rtems__) */ - -/* #endif __STRICT_ANSI__ */ +#endif /* __POSIX_VISIBLE >= 199309 */ #if defined(___AM29K__) /* These all need to be defined for ANSI C, but I don't think they are @@ -349,6 +361,12 @@ int _EXFUN(sigqueue, (pid_t pid, int signo, const union sigval value)); } #endif +#if defined(__CYGWIN__) +#if __XSI_VISIBLE >= 4 || __POSIX_VISIBLE >= 200809 +#include +#endif +#endif + #ifndef _SIGNAL_H_ /* Some applications take advantage of the fact that * and are equivalent in glibc. Allow for that here. */ diff --git a/libc/xtensa-lx106-elf/include/sys/stat.h b/libc/xtensa-lx106-elf/include/sys/stat.h index 11b9d80..94a90c0 100644 --- a/libc/xtensa-lx106-elf/include/sys/stat.h +++ b/libc/xtensa-lx106-elf/include/sys/stat.h @@ -9,6 +9,7 @@ extern "C" { #include #include #include +#include /* dj's stat defines _STAT_H_ */ #ifndef _STAT_H_ @@ -52,8 +53,8 @@ struct stat long st_spare2; time_t st_ctime; long st_spare3; - long st_blksize; - long st_blocks; + blksize_t st_blksize; + blkcnt_t st_blocks; long st_spare4[2]; #endif #endif @@ -81,12 +82,12 @@ struct stat #define S_ISUID 0004000 /* set user id on execution */ #define S_ISGID 0002000 /* set group id on execution */ #define S_ISVTX 0001000 /* save swapped text even after use */ -#ifndef _POSIX_SOURCE +#if __BSD_VISIBLE #define S_IREAD 0000400 /* read permission, owner */ #define S_IWRITE 0000200 /* write permission, owner */ #define S_IEXEC 0000100 /* execute/search permission, owner */ #define S_ENFMT 0002000 /* enforcement-mode locking */ -#endif /* !_POSIX_SOURCE */ +#endif /* !_BSD_VISIBLE */ #define S_IFMT _IFMT #define S_IFDIR _IFDIR @@ -123,7 +124,7 @@ struct stat #define S_IWOTH 0000002 /* write permission, other */ #define S_IXOTH 0000001/* execute/search permission, other */ -#ifndef _POSIX_SOURCE +#if __BSD_VISIBLE #define ACCESSPERMS (S_IRWXU | S_IRWXG | S_IRWXO) /* 0777 */ #define ALLPERMS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) /* 07777 */ #define DEFFILEMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH) /* 0666 */ @@ -156,19 +157,15 @@ int _EXFUN(lstat,( const char *__restrict __path, struct stat *__restrict __buf int _EXFUN(mknod,( const char *__path, mode_t __mode, dev_t __dev )); #endif -#if (__POSIX_VISIBLE >= 200809 || defined (__CYGWIN__)) && !defined(__INSIDE_CYGWIN__) +#if __ATFILE_VISIBLE && !defined(__INSIDE_CYGWIN__) int _EXFUN(fchmodat, (int, const char *, mode_t, int)); -#endif -#if (__BSD_VISIBLE || __POSIX_VISIBLE >= 200809 || defined (__CYGWIN__)) && !defined(__INSIDE_CYGWIN__) int _EXFUN(fstatat, (int, const char *__restrict , struct stat *__restrict, int)); int _EXFUN(mkdirat, (int, const char *, mode_t)); int _EXFUN(mkfifoat, (int, const char *, mode_t)); -#endif -#if (__BSD_VISIBLE || __XSI_VISIBLE >= 700 || defined (__CYGWIN__)) && !defined(__INSIDE_CYGWIN__) int _EXFUN(mknodat, (int, const char *, mode_t, dev_t)); -#endif -#if (__BSD_VISIBLE || __POSIX_VISIBLE >= 200809 || defined (__CYGWIN__)) && !defined(__INSIDE_CYGWIN__) int _EXFUN(utimensat, (int, const char *, const struct timespec *, int)); +#endif +#if __POSIX_VISIBLE >= 200809 && !defined(__INSIDE_CYGWIN__) int _EXFUN(futimens, (int, const struct timespec *)); #endif diff --git a/libc/xtensa-lx106-elf/include/sys/time.h b/libc/xtensa-lx106-elf/include/sys/time.h index be16497..5fdb667 100644 --- a/libc/xtensa-lx106-elf/include/sys/time.h +++ b/libc/xtensa-lx106-elf/include/sys/time.h @@ -2,90 +2,301 @@ Written by Geoffrey Noer Public domain; no rights reserved. */ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)time.h 8.5 (Berkeley) 5/4/95 + * $FreeBSD$ + */ + #ifndef _SYS_TIME_H_ -#define _SYS_TIME_H_ +#define _SYS_TIME_H_ #include <_ansi.h> +#include +#include #include +#include -#ifdef __cplusplus -extern "C" { +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE +#include #endif -#ifndef _TIMEVAL_DEFINED -#define _TIMEVAL_DEFINED -struct timeval { - time_t tv_sec; - suseconds_t tv_usec; -}; - -/* BSD time macros used by RTEMS code */ -#if defined (__rtems__) || defined (__CYGWIN__) - -/* Convenience macros for operations on timevals. - NOTE: `timercmp' does not work for >= or <=. */ -#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) -#define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0) -#define timercmp(a, b, CMP) \ - (((a)->tv_sec == (b)->tv_sec) ? \ - ((a)->tv_usec CMP (b)->tv_usec) : \ - ((a)->tv_sec CMP (b)->tv_sec)) -#define timeradd(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ - if ((result)->tv_usec >= 1000000) \ - { \ - ++(result)->tv_sec; \ - (result)->tv_usec -= 1000000; \ - } \ - } while (0) -#define timersub(a, b, result) \ - do { \ - (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ - (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ - if ((result)->tv_usec < 0) { \ - --(result)->tv_sec; \ - (result)->tv_usec += 1000000; \ - } \ - } while (0) -#endif /* defined (__rtems__) || defined (__CYGWIN__) */ -#endif /* !_TIMEVAL_DEFINED */ - struct timezone { - int tz_minuteswest; - int tz_dsttime; + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; +#define DST_NONE 0 /* not on dst */ +#define DST_USA 1 /* USA style dst */ +#define DST_AUST 2 /* Australian style dst */ +#define DST_WET 3 /* Western European dst */ +#define DST_MET 4 /* Middle European dst */ +#define DST_EET 5 /* Eastern European dst */ +#define DST_CAN 6 /* Canada */ + +#if __BSD_VISIBLE +struct bintime { + time_t sec; + uint64_t frac; }; -#ifdef __CYGWIN__ -#include -#endif /* __CYGWIN__ */ +static __inline void +bintime_addx(struct bintime *_bt, uint64_t _x) +{ + uint64_t _u; -#define ITIMER_REAL 0 -#define ITIMER_VIRTUAL 1 -#define ITIMER_PROF 2 + _u = _bt->frac; + _bt->frac += _x; + if (_u > _bt->frac) + _bt->sec++; +} -struct itimerval { - struct timeval it_interval; - struct timeval it_value; +static __inline void +bintime_add(struct bintime *_bt, const struct bintime *_bt2) +{ + uint64_t _u; + + _u = _bt->frac; + _bt->frac += _bt2->frac; + if (_u > _bt->frac) + _bt->sec++; + _bt->sec += _bt2->sec; +} + +static __inline void +bintime_sub(struct bintime *_bt, const struct bintime *_bt2) +{ + uint64_t _u; + + _u = _bt->frac; + _bt->frac -= _bt2->frac; + if (_u < _bt->frac) + _bt->sec--; + _bt->sec -= _bt2->sec; +} + +static __inline void +bintime_mul(struct bintime *_bt, u_int _x) +{ + uint64_t _p1, _p2; + + _p1 = (_bt->frac & 0xffffffffull) * _x; + _p2 = (_bt->frac >> 32) * _x + (_p1 >> 32); + _bt->sec *= _x; + _bt->sec += (_p2 >> 32); + _bt->frac = (_p2 << 32) | (_p1 & 0xffffffffull); +} + +static __inline void +bintime_shift(struct bintime *_bt, int _exp) +{ + + if (_exp > 0) { + _bt->sec <<= _exp; + _bt->sec |= _bt->frac >> (64 - _exp); + _bt->frac <<= _exp; + } else if (_exp < 0) { + _bt->frac >>= -_exp; + _bt->frac |= (uint64_t)_bt->sec << (64 + _exp); + _bt->sec >>= -_exp; + } +} + +#define bintime_clear(a) ((a)->sec = (a)->frac = 0) +#define bintime_isset(a) ((a)->sec || (a)->frac) +#define bintime_cmp(a, b, cmp) \ + (((a)->sec == (b)->sec) ? \ + ((a)->frac cmp (b)->frac) : \ + ((a)->sec cmp (b)->sec)) + +#define SBT_1S ((sbintime_t)1 << 32) +#define SBT_1M (SBT_1S * 60) +#define SBT_1MS (SBT_1S / 1000) +#define SBT_1US (SBT_1S / 1000000) +#define SBT_1NS (SBT_1S / 1000000000) +#define SBT_MAX 0x7fffffffffffffffLL + +static __inline int +sbintime_getsec(sbintime_t _sbt) +{ + + return (_sbt >> 32); +} + +static __inline sbintime_t +bttosbt(const struct bintime _bt) +{ + + return (((sbintime_t)_bt.sec << 32) + (_bt.frac >> 32)); +} + +static __inline struct bintime +sbttobt(sbintime_t _sbt) +{ + struct bintime _bt; + + _bt.sec = _sbt >> 32; + _bt.frac = _sbt << 32; + return (_bt); +} + +/*- + * Background information: + * + * When converting between timestamps on parallel timescales of differing + * resolutions it is historical and scientific practice to round down rather + * than doing 4/5 rounding. + * + * The date changes at midnight, not at noon. + * + * Even at 15:59:59.999999999 it's not four'o'clock. + * + * time_second ticks after N.999999999 not after N.4999999999 + */ + +static __inline void +bintime2timespec(const struct bintime *_bt, struct timespec *_ts) +{ + + _ts->tv_sec = _bt->sec; + _ts->tv_nsec = ((uint64_t)1000000000 * + (uint32_t)(_bt->frac >> 32)) >> 32; +} + +static __inline void +timespec2bintime(const struct timespec *_ts, struct bintime *_bt) +{ + + _bt->sec = _ts->tv_sec; + /* 18446744073 = int(2^64 / 1000000000) */ + _bt->frac = _ts->tv_nsec * (uint64_t)18446744073LL; +} + +static __inline void +bintime2timeval(const struct bintime *_bt, struct timeval *_tv) +{ + + _tv->tv_sec = _bt->sec; + _tv->tv_usec = ((uint64_t)1000000 * (uint32_t)(_bt->frac >> 32)) >> 32; +} + +static __inline void +timeval2bintime(const struct timeval *_tv, struct bintime *_bt) +{ + + _bt->sec = _tv->tv_sec; + /* 18446744073709 = int(2^64 / 1000000) */ + _bt->frac = _tv->tv_usec * (uint64_t)18446744073709LL; +} + +static __inline struct timespec +sbttots(sbintime_t _sbt) +{ + struct timespec _ts; + + _ts.tv_sec = _sbt >> 32; + _ts.tv_nsec = ((uint64_t)1000000000 * (uint32_t)_sbt) >> 32; + return (_ts); +} + +static __inline sbintime_t +tstosbt(struct timespec _ts) +{ + + return (((sbintime_t)_ts.tv_sec << 32) + + (_ts.tv_nsec * (((uint64_t)1 << 63) / 500000000) >> 32)); +} + +static __inline struct timeval +sbttotv(sbintime_t _sbt) +{ + struct timeval _tv; + + _tv.tv_sec = _sbt >> 32; + _tv.tv_usec = ((uint64_t)1000000 * (uint32_t)_sbt) >> 32; + return (_tv); +} + +static __inline sbintime_t +tvtosbt(struct timeval _tv) +{ + + return (((sbintime_t)_tv.tv_sec << 32) + + (_tv.tv_usec * (((uint64_t)1 << 63) / 500000) >> 32)); +} +#endif /* __BSD_VISIBLE */ + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ }; +#ifndef _KERNEL +#include + +__BEGIN_DECLS +int _EXFUN(utimes, (const char *__path, const struct timeval *__tvp)); + +#if __BSD_VISIBLE +int _EXFUN(adjtime, (const struct timeval *, struct timeval *)); +int _EXFUN(futimes, (int, const struct timeval *)); +int _EXFUN(lutimes, (const char *, const struct timeval *)); +int _EXFUN(settimeofday, (const struct timeval *, const struct timezone *)); +#endif + +#if __MISC_VISIBLE || __XSI_VISIBLE +int _EXFUN(getitimer, (int __which, struct itimerval *__value)); +int _EXFUN(setitimer, (int __which, const struct itimerval *__restrict __value, + struct itimerval *__restrict __ovalue)); +#endif + +int _EXFUN(gettimeofday, (struct timeval *__restrict __p, + void *__restrict __tz)); + +#if __GNU_VISIBLE +int _EXFUN(futimesat, (int, const char *, const struct timeval [2])); +#endif + #ifdef _COMPILING_NEWLIB int _EXFUN(_gettimeofday, (struct timeval *__p, void *__tz)); #endif -int _EXFUN(gettimeofday, (struct timeval *__restrict __p, - void *__restrict __tz)); -#if __BSD_VISIBLE -int _EXFUN(settimeofday, (const struct timeval *, const struct timezone *)); -int _EXFUN(adjtime, (const struct timeval *, struct timeval *)); -#endif -int _EXFUN(utimes, (const char *__path, const struct timeval *__tvp)); -int _EXFUN(getitimer, (int __which, struct itimerval *__value)); -int _EXFUN(setitimer, (int __which, const struct itimerval *__restrict __value, - struct itimerval *__restrict __ovalue)); +__END_DECLS -#ifdef __cplusplus -} -#endif -#endif /* _SYS_TIME_H_ */ +#endif /* !_KERNEL */ +#include + +#endif /* !_SYS_TIME_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/timeb.h b/libc/xtensa-lx106-elf/include/sys/timeb.h index 0a2c3de..793b481 100644 --- a/libc/xtensa-lx106-elf/include/sys/timeb.h +++ b/libc/xtensa-lx106-elf/include/sys/timeb.h @@ -15,11 +15,12 @@ extern "C" { #define _SYS_TIMEB_H #include <_ansi.h> -#include +#include -#ifndef __time_t_defined -typedef _TIME_T_ time_t; -#define __time_t_defined +#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED) +typedef _TIME_T_ time_t; +#define __time_t_defined +#define _TIME_T_DECLARED #endif struct timeb diff --git a/libc/xtensa-lx106-elf/include/sys/times.h b/libc/xtensa-lx106-elf/include/sys/times.h index 927812c..b1f1dc6 100644 --- a/libc/xtensa-lx106-elf/include/sys/times.h +++ b/libc/xtensa-lx106-elf/include/sys/times.h @@ -5,11 +5,12 @@ extern "C" { #define _SYS_TIMES_H #include <_ansi.h> -#include +#include -#ifndef __clock_t_defined -typedef _CLOCK_T_ clock_t; -#define __clock_t_defined +#if !defined(__clock_t_defined) && !defined(_CLOCK_T_DECLARED) +typedef _CLOCK_T_ clock_t; +#define __clock_t_defined +#define _CLOCK_T_DECLARED #endif /* Get Process Times, P1003.1b-1993, p. 92 */ diff --git a/libc/xtensa-lx106-elf/include/sys/timespec.h b/libc/xtensa-lx106-elf/include/sys/timespec.h new file mode 100644 index 0000000..2505cef --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/timespec.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. 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. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)time.h 8.5 (Berkeley) 5/4/95 + * from: FreeBSD: src/sys/sys/time.h,v 1.43 2000/03/20 14:09:05 phk Exp + * $FreeBSD$ + */ + +#ifndef _SYS_TIMESPEC_H_ +#define _SYS_TIMESPEC_H_ + +#include +#include + +#if __BSD_VISIBLE +#define TIMEVAL_TO_TIMESPEC(tv, ts) \ + do { \ + (ts)->tv_sec = (tv)->tv_sec; \ + (ts)->tv_nsec = (tv)->tv_usec * 1000; \ + } while (0) +#define TIMESPEC_TO_TIMEVAL(tv, ts) \ + do { \ + (tv)->tv_sec = (ts)->tv_sec; \ + (tv)->tv_usec = (ts)->tv_nsec / 1000; \ + } while (0) + +#endif /* __BSD_VISIBLE */ + +/* + * Structure defined by POSIX.1b to be like a itimerval, but with + * timespecs. Used in the timer_*() system calls. + */ +struct itimerspec { + struct timespec it_interval; + struct timespec it_value; +}; + +#endif /* _SYS_TIMESPEC_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/tree.h b/libc/xtensa-lx106-elf/include/sys/tree.h new file mode 100644 index 0000000..f4167c4 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/sys/tree.h @@ -0,0 +1,801 @@ +/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* $FreeBSD$ */ + +/*- + * Copyright 2002 Niels Provos + * 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. + * + * 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. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +#include + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ + RB_PROTOTYPE_INSERT_COLOR(name, type, attr); \ + RB_PROTOTYPE_REMOVE_COLOR(name, type, attr); \ + RB_PROTOTYPE_INSERT(name, type, attr); \ + RB_PROTOTYPE_REMOVE(name, type, attr); \ + RB_PROTOTYPE_FIND(name, type, attr); \ + RB_PROTOTYPE_NFIND(name, type, attr); \ + RB_PROTOTYPE_NEXT(name, type, attr); \ + RB_PROTOTYPE_PREV(name, type, attr); \ + RB_PROTOTYPE_MINMAX(name, type, attr); +#define RB_PROTOTYPE_INSERT_COLOR(name, type, attr) \ + attr void name##_RB_INSERT_COLOR(struct name *, struct type *) +#define RB_PROTOTYPE_REMOVE_COLOR(name, type, attr) \ + attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *) +#define RB_PROTOTYPE_REMOVE(name, type, attr) \ + attr struct type *name##_RB_REMOVE(struct name *, struct type *) +#define RB_PROTOTYPE_INSERT(name, type, attr) \ + attr struct type *name##_RB_INSERT(struct name *, struct type *) +#define RB_PROTOTYPE_FIND(name, type, attr) \ + attr struct type *name##_RB_FIND(struct name *, struct type *) +#define RB_PROTOTYPE_NFIND(name, type, attr) \ + attr struct type *name##_RB_NFIND(struct name *, struct type *) +#define RB_PROTOTYPE_NEXT(name, type, attr) \ + attr struct type *name##_RB_NEXT(struct type *) +#define RB_PROTOTYPE_PREV(name, type, attr) \ + attr struct type *name##_RB_PREV(struct type *) +#define RB_PROTOTYPE_MINMAX(name, type, attr) \ + attr struct type *name##_RB_MINMAX(struct name *, int) + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ + RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ + RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ + RB_GENERATE_INSERT(name, type, field, cmp, attr) \ + RB_GENERATE_REMOVE(name, type, field, attr) \ + RB_GENERATE_FIND(name, type, field, cmp, attr) \ + RB_GENERATE_NFIND(name, type, field, cmp, attr) \ + RB_GENERATE_NEXT(name, type, field, attr) \ + RB_GENERATE_PREV(name, type, field, attr) \ + RB_GENERATE_MINMAX(name, type, field, attr) + +#define RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} + +#define RB_GENERATE_REMOVE_COLOR(name, type, field, attr) \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} + +#define RB_GENERATE_REMOVE(name, type, field, attr) \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + +#define RB_GENERATE_INSERT(name, type, field, cmp, attr) \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} + +#define RB_GENERATE_FIND(name, type, field, cmp, attr) \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} + +#define RB_GENERATE_NFIND(name, type, field, cmp, attr) \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} + +#define RB_GENERATE_NEXT(name, type, field, attr) \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} + +#define RB_GENERATE_PREV(name, type, field, attr) \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} + +#define RB_GENERATE_MINMAX(name, type, field, attr) \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* _SYS_TREE_H_ */ diff --git a/libc/xtensa-lx106-elf/include/sys/types.h b/libc/xtensa-lx106-elf/include/sys/types.h index ed33e0a..65ff520 100644 --- a/libc/xtensa-lx106-elf/include/sys/types.h +++ b/libc/xtensa-lx106-elf/include/sys/types.h @@ -18,20 +18,12 @@ #ifndef _SYS_TYPES_H #include <_ansi.h> - -#ifndef __INTTYPES_DEFINED__ -#define __INTTYPES_DEFINED__ - +#include #include -#if defined(__rtems__) || defined(__XMK__) -/* - * The following section is RTEMS specific and is needed to more - * closely match the types defined in the BSD sys/types.h. - * This is needed to let the RTEMS/BSD TCP/IP stack compile. - */ - -/* deprecated */ +/* BSD types permitted by POSIX and always exposed as in Glibc. Only provided + for backward compatibility with BSD code. The uintN_t standard types should + be preferred in new code. */ #if ___int8_t_defined typedef __uint8_t u_int8_t; #endif @@ -41,52 +33,54 @@ typedef __uint16_t u_int16_t; #if ___int32_t_defined typedef __uint32_t u_int32_t; #endif - #if ___int64_t_defined typedef __uint64_t u_int64_t; +#endif +typedef int register_t; +#define __BIT_TYPES_DEFINED__ 1 + +#if defined(__rtems__) || defined(__XMK__) +/* + * The following section is RTEMS specific and is needed to more + * closely match the types defined in the BSD sys/types.h. + * This is needed to let the RTEMS/BSD TCP/IP stack compile. + */ /* deprecated */ +#if ___int64_t_defined typedef __uint64_t u_quad_t; typedef __int64_t quad_t; typedef quad_t * qaddr_t; #endif -#endif - -#endif /* ! __INTTYPES_DEFINED */ +#endif /* __rtems__ || __XMK__ */ #ifndef __need_inttypes #define _SYS_TYPES_H +/* must be before for __size_t considerations */ +#include #include +#include -#ifdef __i386__ -#if defined (GO32) || defined (__MSDOS__) -#define __MS_types__ -#endif -#endif - -# include -# include - -/* To ensure the stat struct's layout doesn't change when sizeof(int), etc. - changes, we assume sizeof short and long never change and have all types - used to define struct stat use them and not int where possible. - Where not possible, _ST_INTxx are used. It would be preferable to not have - such assumptions, but until the extra fluff is necessary, it's avoided. - No 64 bit targets use stat yet. What to do about them is postponed - until necessary. */ -#ifdef __GNUC__ -#define _ST_INT32 __attribute__ ((__mode__ (__SI__))) -#else -#define _ST_INT32 -#endif - -# ifndef _POSIX_SOURCE - +#if __BSD_VISIBLE +#include +#include # define physadr physadr_t # define quad quad_t +#ifndef _IN_ADDR_T_DECLARED +typedef __uint32_t in_addr_t; /* base type for internet address */ +#define _IN_ADDR_T_DECLARED +#endif + +#ifndef _IN_PORT_T_DECLARED +typedef __uint16_t in_port_t; +#define _IN_PORT_T_DECLARED +#endif +#endif /* __BSD_VISIBLE */ + +#if __MISC_VISIBLE #ifndef _BSDTYPES_DEFINED /* also defined in mingw/gmon.h and in w32api/winsock[2].h */ #ifndef __u_char_defined @@ -107,36 +101,35 @@ typedef unsigned long u_long; #endif #define _BSDTYPES_DEFINED #endif +#endif /*__BSD_VISIBLE || __CYGWIN__ */ +#if __MISC_VISIBLE typedef unsigned short ushort; /* System V compatibility */ typedef unsigned int uint; /* System V compatibility */ typedef unsigned long ulong; /* System V compatibility */ -# endif /*!_POSIX_SOURCE */ - -#ifndef __clock_t_defined -typedef _CLOCK_T_ clock_t; -#define __clock_t_defined #endif -#ifndef __time_t_defined -typedef _TIME_T_ time_t; -#define __time_t_defined +#ifndef _BLKCNT_T_DECLARED +typedef __blkcnt_t blkcnt_t; +#define _BLKCNT_T_DECLARED #endif -#ifndef __timespec_defined -#define __timespec_defined -/* Time Value Specification Structures, P1003.1b-1993, p. 261 */ - -struct timespec { - time_t tv_sec; /* Seconds */ - long tv_nsec; /* Nanoseconds */ -}; +#ifndef _BLKSIZE_T_DECLARED +typedef __blksize_t blksize_t; +#define _BLKSIZE_T_DECLARED #endif -struct itimerspec { - struct timespec it_interval; /* Timer period */ - struct timespec it_value; /* Timer expiration */ -}; +#if !defined(__clock_t_defined) && !defined(_CLOCK_T_DECLARED) +typedef _CLOCK_T_ clock_t; +#define __clock_t_defined +#define _CLOCK_T_DECLARED +#endif + +#if !defined(__time_t_defined) && !defined(_TIME_T_DECLARED) +typedef _TIME_T_ time_t; +#define __time_t_defined +#define _TIME_T_DECLARED +#endif #ifndef __daddr_t_defined typedef long daddr_t; @@ -147,31 +140,27 @@ typedef char * caddr_t; #define __caddr_t_defined #endif -#ifndef __CYGWIN__ -#if defined(__MS_types__) || defined(__rtems__) || \ - defined(__sparc__) || defined(__SPU__) -typedef unsigned long ino_t; -#else -typedef unsigned short ino_t; +#ifndef _FSBLKCNT_T_DECLARED /* for statvfs() */ +typedef __fsblkcnt_t fsblkcnt_t; +typedef __fsfilcnt_t fsfilcnt_t; +#define _FSBLKCNT_T_DECLARED #endif -#endif /*__CYGWIN__*/ -#ifdef __MS_types__ +#ifndef _ID_T_DECLARED +typedef __id_t id_t; /* can hold a uid_t or pid_t */ +#define _ID_T_DECLARED +#endif + +#ifndef _INO_T_DECLARED +typedef __ino_t ino_t; /* inode number */ +#define _INO_T_DECLARED +#endif + +#if defined(__i386__) && (defined(GO32) || defined(__MSDOS__)) +typedef char * addr_t; typedef unsigned long vm_offset_t; typedef unsigned long vm_size_t; - -#define __BIT_TYPES_DEFINED__ - -typedef signed char int8_t; -typedef unsigned char u_int8_t; -typedef short int16_t; -typedef unsigned short u_int16_t; -typedef int int32_t; -typedef unsigned int u_int32_t; -typedef long long int64_t; -typedef unsigned long long u_int64_t; -typedef int32_t register_t; -#endif /* __MS_types__ */ +#endif /* __i386__ && (GO32 || __MSDOS__) */ /* * All these should be machine specific - right now they are all broken. @@ -180,339 +169,75 @@ typedef int32_t register_t; * how the file was compiled (e.g. -mint16 vs -mint32, etc.). */ -#ifndef __CYGWIN__ /* which defines these types in it's own types.h. */ -typedef _off_t off_t; -typedef __dev_t dev_t; -typedef __uid_t uid_t; -typedef __gid_t gid_t; +#ifndef _OFF_T_DECLARED +typedef __off_t off_t; /* file offset */ +#define _OFF_T_DECLARED +#endif +#ifndef _DEV_T_DECLARED +typedef __dev_t dev_t; /* device number or struct cdev */ +#define _DEV_T_DECLARED +#endif +#ifndef _UID_T_DECLARED +typedef __uid_t uid_t; /* user id */ +#define _UID_T_DECLARED +#endif +#ifndef _GID_T_DECLARED +typedef __gid_t gid_t; /* group id */ +#define _GID_T_DECLARED #endif -#if defined(__XMK__) -typedef signed char pid_t; -#else -typedef int pid_t; +#ifndef _PID_T_DECLARED +typedef __pid_t pid_t; /* process id */ +#define _PID_T_DECLARED #endif -#if defined(__rtems__) -typedef _mode_t mode_t; +#ifndef _KEY_T_DECLARED +typedef __key_t key_t; /* IPC key */ +#define _KEY_T_DECLARED #endif -#ifndef __CYGWIN__ -typedef long key_t; -#endif +#ifndef _SSIZE_T_DECLARED typedef _ssize_t ssize_t; - -#if !defined(__CYGWIN__) && !defined(__rtems__) -#ifdef __MS_types__ -typedef char * addr_t; -typedef int mode_t; -#else -#if defined (__sparc__) && !defined (__sparc_v9__) -#ifdef __svr4__ -typedef unsigned long mode_t; -#else -typedef unsigned short mode_t; -#endif -#else -typedef unsigned int mode_t _ST_INT32; -#endif -#endif /* ! __MS_types__ */ -#endif /*__CYGWIN__*/ - -typedef unsigned short nlink_t; - -/* We don't define fd_set and friends if we are compiling POSIX - source, or if we have included (or may include as indicated - by __USE_W32_SOCKETS) the W32api winsock[2].h header which - defines Windows versions of them. Note that a program which - includes the W32api winsock[2].h header must know what it is doing; - it must not call the cygwin32 select function. -*/ -# if !(defined (_POSIX_SOURCE) || defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) -# define _SYS_TYPES_FD_SET -# define NBBY 8 /* number of bits in a byte */ -/* - * Select uses bit masks of file descriptors in longs. - * These macros manipulate such bit fields (the filesystem macros use chars). - * FD_SETSIZE may be defined by the user, but the default here - * should be >= NOFILE (param.h). - */ -# ifndef FD_SETSIZE -# define FD_SETSIZE 64 -# endif - -typedef long fd_mask; -# define NFDBITS (sizeof (fd_mask) * NBBY) /* bits per mask */ -# ifndef howmany -# define howmany(x,y) (((x)+((y)-1))/(y)) -# endif - -/* We use a macro for fd_set so that including Sockets.h afterwards - can work. */ -typedef struct _types_fd_set { - fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)]; -} _types_fd_set; - -#define fd_set _types_fd_set - -# define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1L << ((n) % NFDBITS))) -# define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1L << ((n) % NFDBITS))) -# define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1L << ((n) % NFDBITS))) -# define FD_ZERO(p) (__extension__ (void)({ \ - size_t __i; \ - char *__tmp = (char *)p; \ - for (__i = 0; __i < sizeof (*(p)); ++__i) \ - *__tmp++ = 0; \ -})) - -# endif /* !(defined (_POSIX_SOURCE) || defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) */ - -#undef __MS_types__ -#undef _ST_INT32 - - -#ifndef __clockid_t_defined -typedef _CLOCKID_T_ clockid_t; -#define __clockid_t_defined +#define _SSIZE_T_DECLARED #endif -#ifndef __timer_t_defined -typedef _TIMER_T_ timer_t; -#define __timer_t_defined +#ifndef _MODE_T_DECLARED +typedef __mode_t mode_t; /* permissions */ +#define _MODE_T_DECLARED #endif -typedef unsigned long useconds_t; -typedef long suseconds_t; +#ifndef _NLINK_T_DECLARED +typedef __nlink_t nlink_t; /* link count */ +#define _NLINK_T_DECLARED +#endif + +#if !defined(__clockid_t_defined) && !defined(_CLOCKID_T_DECLARED) +typedef __clockid_t clockid_t; +#define __clockid_t_defined +#define _CLOCKID_T_DECLARED +#endif + +#if !defined(__timer_t_defined) && !defined(_TIMER_T_DECLARED) +typedef __timer_t timer_t; +#define __timer_t_defined +#define _TIMER_T_DECLARED +#endif + +#ifndef _USECONDS_T_DECLARED +typedef __useconds_t useconds_t; /* microseconds (unsigned) */ +#define _USECONDS_T_DECLARED +#endif + +#ifndef _SUSECONDS_T_DECLARED +typedef __suseconds_t suseconds_t; +#define _SUSECONDS_T_DECLARED +#endif + +typedef __int64_t sbintime_t; #include - - -/* Cygwin will probably never have full posix compliance due to little things - * like an inability to set the stackaddress. Cygwin is also using void * - * pointers rather than structs to ensure maximum binary compatability with - * previous releases. - * This means that we don't use the types defined here, but rather in - * - */ -#if defined(_POSIX_THREADS) && !defined(__CYGWIN__) - -#include - -/* - * 2.5 Primitive System Data Types, P1003.1c/D10, p. 19. - */ - -#if defined(__XMK__) -typedef unsigned int pthread_t; /* identify a thread */ -#else -typedef __uint32_t pthread_t; /* identify a thread */ -#endif - -/* P1003.1c/D10, p. 118-119 */ -#define PTHREAD_SCOPE_PROCESS 0 -#define PTHREAD_SCOPE_SYSTEM 1 - -/* P1003.1c/D10, p. 111 */ -#define PTHREAD_INHERIT_SCHED 1 /* scheduling policy and associated */ - /* attributes are inherited from */ - /* the calling thread. */ -#define PTHREAD_EXPLICIT_SCHED 2 /* set from provided attribute object */ - -/* P1003.1c/D10, p. 141 */ -#define PTHREAD_CREATE_DETACHED 0 -#define PTHREAD_CREATE_JOINABLE 1 - -#if defined(__rtems__) - #include -#endif - -#if defined(__XMK__) -typedef struct pthread_attr_s { - int contentionscope; - struct sched_param schedparam; - int detachstate; - void *stackaddr; - size_t stacksize; -} pthread_attr_t; - -#define PTHREAD_STACK_MIN 200 - -#else /* !defined(__XMK__) */ -typedef struct { - int is_initialized; - void *stackaddr; - int stacksize; - int contentionscope; - int inheritsched; - int schedpolicy; - struct sched_param schedparam; -#if defined(__rtems__) - size_t guardsize; -#endif - - /* P1003.4b/D8, p. 54 adds cputime_clock_allowed attribute. */ -#if defined(_POSIX_THREAD_CPUTIME) - int cputime_clock_allowed; /* see time.h */ -#endif - int detachstate; -#if defined(__rtems__) - size_t affinitysetsize; - cpu_set_t *affinityset; - cpu_set_t affinitysetpreallocated; -#endif -} pthread_attr_t; - -#endif /* !defined(__XMK__) */ - -#if defined(_POSIX_THREAD_PROCESS_SHARED) -/* NOTE: P1003.1c/D10, p. 81 defines following values for process_shared. */ - -#define PTHREAD_PROCESS_PRIVATE 0 /* visible within only the creating process */ -#define PTHREAD_PROCESS_SHARED 1 /* visible too all processes with access to */ - /* the memory where the resource is */ - /* located */ -#endif - -#if defined(_POSIX_THREAD_PRIO_PROTECT) -/* Mutexes */ - -/* Values for blocking protocol. */ - -#define PTHREAD_PRIO_NONE 0 -#define PTHREAD_PRIO_INHERIT 1 -#define PTHREAD_PRIO_PROTECT 2 -#endif - -#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) - -/* Values for mutex type */ - -/* The following defines are part of the X/Open System Interface (XSI). */ - -/* - * This type of mutex does not detect deadlock. A thread attempting to - * relock this mutex without first unlocking it shall deadlock. Attempting - * to unlock a mutex locked by a different thread results in undefined - * behavior. Attempting to unlock an unlocked mutex results in undefined - * behavior. - */ -#define PTHREAD_MUTEX_NORMAL 0 - -/* - * A thread attempting to relock this mutex without first unlocking - * it shall succeed in locking the mutex. The relocking deadlock which - * can occur with mutexes of type PTHREAD_MUTEX_NORMAL cannot occur with - * this type of mutex. Multiple locks of this mutex shall require the - * same number of unlocks to release the mutex before another thread can - * acquire the mutex. A thread attempting to unlock a mutex which another - * thread has locked shall return with an error. A thread attempting to - * unlock an unlocked mutex shall return with an error. - */ -#define PTHREAD_MUTEX_RECURSIVE 1 - -/* - * This type of mutex provides error checking. A thread attempting - * to relock this mutex without first unlocking it shall return with an - * error. A thread attempting to unlock a mutex which another thread has - * locked shall return with an error. A thread attempting to unlock an - * unlocked mutex shall return with an error. - */ -#define PTHREAD_MUTEX_ERRORCHECK 2 - -/* - * Attempting to recursively lock a mutex of this type results - * in undefined behavior. Attempting to unlock a mutex of this type - * which was not locked by the calling thread results in undefined - * behavior. Attempting to unlock a mutex of this type which is not locked - * results in undefined behavior. An implementation may map this mutex to - * one of the other mutex types. - */ -#define PTHREAD_MUTEX_DEFAULT 3 - -#endif /* !defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) */ - -#if defined(__XMK__) -typedef unsigned int pthread_mutex_t; /* identify a mutex */ - -typedef struct { - int type; -} pthread_mutexattr_t; - -#else /* !defined(__XMK__) */ -typedef __uint32_t pthread_mutex_t; /* identify a mutex */ - -typedef struct { - int is_initialized; -#if defined(_POSIX_THREAD_PROCESS_SHARED) - int process_shared; /* allow mutex to be shared amongst processes */ -#endif -#if defined(_POSIX_THREAD_PRIO_PROTECT) - int prio_ceiling; - int protocol; -#endif -#if defined(_UNIX98_THREAD_MUTEX_ATTRIBUTES) - int type; -#endif - int recursive; -} pthread_mutexattr_t; -#endif /* !defined(__XMK__) */ - -/* Condition Variables */ - -typedef __uint32_t pthread_cond_t; /* identify a condition variable */ - -typedef struct { - int is_initialized; -#if defined(_POSIX_THREAD_PROCESS_SHARED) - int process_shared; /* allow this to be shared amongst processes */ -#endif -} pthread_condattr_t; /* a condition attribute object */ - -/* Keys */ - -typedef __uint32_t pthread_key_t; /* thread-specific data keys */ - -typedef struct { - int is_initialized; /* is this structure initialized? */ - int init_executed; /* has the initialization routine been run? */ -} pthread_once_t; /* dynamic package initialization */ -#else -#if defined (__CYGWIN__) -#include -#endif -#endif /* defined(_POSIX_THREADS) */ - -/* POSIX Barrier Types */ - -#if defined(_POSIX_BARRIERS) -typedef __uint32_t pthread_barrier_t; /* POSIX Barrier Object */ -typedef struct { - int is_initialized; /* is this structure initialized? */ -#if defined(_POSIX_THREAD_PROCESS_SHARED) - int process_shared; /* allow this to be shared amongst processes */ -#endif -} pthread_barrierattr_t; -#endif /* defined(_POSIX_BARRIERS) */ - -/* POSIX Spin Lock Types */ - -#if !defined (__CYGWIN__) -#if defined(_POSIX_SPIN_LOCKS) -typedef __uint32_t pthread_spinlock_t; /* POSIX Spin Lock Object */ -#endif /* defined(_POSIX_SPIN_LOCKS) */ - -/* POSIX Reader/Writer Lock Types */ - -#if defined(_POSIX_READER_WRITER_LOCKS) -typedef __uint32_t pthread_rwlock_t; /* POSIX RWLock Object */ -typedef struct { - int is_initialized; /* is this structure initialized? */ -#if defined(_POSIX_THREAD_PROCESS_SHARED) - int process_shared; /* allow this to be shared amongst processes */ -#endif -} pthread_rwlockattr_t; -#endif /* defined(_POSIX_READER_WRITER_LOCKS) */ -#endif /* __CYGWIN__ */ +#include +#include #endif /* !__need_inttypes */ diff --git a/libc/xtensa-lx106-elf/include/sys/unistd.h b/libc/xtensa-lx106-elf/include/sys/unistd.h index a741383..75f8a51 100644 --- a/libc/xtensa-lx106-elf/include/sys/unistd.h +++ b/libc/xtensa-lx106-elf/include/sys/unistd.h @@ -24,72 +24,89 @@ int _EXFUN(chmod, (const char *__path, mode_t __mode )); #if !defined(__INSIDE_CYGWIN__) int _EXFUN(chown, (const char *__path, uid_t __owner, gid_t __group )); #endif -#if defined(__CYGWIN__) || defined(__rtems__) +#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200112) int _EXFUN(chroot, (const char *__path )); #endif int _EXFUN(close, (int __fildes )); -#if defined(__CYGWIN__) +#if __POSIX_VISIBLE >= 199209 size_t _EXFUN(confstr, (int __name, char *__buf, size_t __len)); #endif +#if __XSI_VISIBLE +char * _EXFUN(crypt, (const char *__key, const char *__salt)); +#endif +#if __XSI_VISIBLE && __XSI_VISIBLE < 700 char * _EXFUN(ctermid, (char *__s )); +#endif +#if __XSI_VISIBLE && __XSI_VISIBLE < 600 char * _EXFUN(cuserid, (char *__s )); -#if defined(__CYGWIN__) +#endif +#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500) int _EXFUN(daemon, (int nochdir, int noclose)); #endif int _EXFUN(dup, (int __fildes )); int _EXFUN(dup2, (int __fildes, int __fildes2 )); -#if defined(__CYGWIN__) +#if __GNU_VISIBLE int _EXFUN(dup3, (int __fildes, int __fildes2, int flags)); int _EXFUN(eaccess, (const char *__path, int __mode)); +#endif +#if __XSI_VISIBLE +void _EXFUN(encrypt, (char *__block, int __edflag)); +#endif +#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500) void _EXFUN(endusershell, (void)); +#endif +#if __GNU_VISIBLE int _EXFUN(euidaccess, (const char *__path, int __mode)); #endif int _EXFUN(execl, (const char *__path, const char *, ... )); int _EXFUN(execle, (const char *__path, const char *, ... )); int _EXFUN(execlp, (const char *__file, const char *, ... )); -#if defined(__CYGWIN__) +#if __MISC_VISIBLE int _EXFUN(execlpe, (const char *__file, const char *, ... )); #endif int _EXFUN(execv, (const char *__path, char * const __argv[] )); int _EXFUN(execve, (const char *__path, char * const __argv[], char * const __envp[] )); int _EXFUN(execvp, (const char *__file, char * const __argv[] )); -#if defined(__CYGWIN__) +#if __GNU_VISIBLE int _EXFUN(execvpe, (const char *__file, char * const __argv[], char * const __envp[] )); #endif -#if __POSIX_VISIBLE >= 200809 || __BSD_VISIBLE || defined(__CYGWIN__) +#if __ATFILE_VISIBLE int _EXFUN(faccessat, (int __dirfd, const char *__path, int __mode, int __flags)); #endif -#if defined(__CYGWIN__) || defined(__rtems__) || defined(__SPU__) +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 int _EXFUN(fchdir, (int __fildes)); #endif int _EXFUN(fchmod, (int __fildes, mode_t __mode )); #if !defined(__INSIDE_CYGWIN__) int _EXFUN(fchown, (int __fildes, uid_t __owner, gid_t __group )); #endif -#if __POSIX_VISIBLE >= 200809 || __BSD_VISIBLE || defined(__CYGWIN__) +#if __ATFILE_VISIBLE int _EXFUN(fchownat, (int __dirfd, const char *__path, uid_t __owner, gid_t __group, int __flags)); #endif -#if defined(__CYGWIN__) +#if __POSIX_VISIBLE >= 200809 int _EXFUN(fexecve, (int __fd, char * const __argv[], char * const __envp[] )); #endif pid_t _EXFUN(fork, (void )); long _EXFUN(fpathconf, (int __fd, int __name )); int _EXFUN(fsync, (int __fd)); int _EXFUN(fdatasync, (int __fd)); -#if defined(__CYGWIN__) +#if __GNU_VISIBLE char * _EXFUN(get_current_dir_name, (void)); #endif char * _EXFUN(getcwd, (char *__buf, size_t __size )); -#if defined(__CYGWIN__) +#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500) int _EXFUN(getdomainname ,(char *__name, size_t __len)); #endif +#if __BSD_VISIBLE +int _EXFUN(getentropy, (void *, size_t)); +#endif #if !defined(__INSIDE_CYGWIN__) gid_t _EXFUN(getegid, (void )); uid_t _EXFUN(geteuid, (void )); gid_t _EXFUN(getgid, (void )); #endif int _EXFUN(getgroups, (int __gidsetsize, gid_t __grouplist[] )); -#if defined(__CYGWIN__) +#if __BSD_VISIBLE || __XSI_VISIBLE >= 4 long _EXFUN(gethostid, (void)); #endif char * _EXFUN(getlogin, (void )); @@ -98,37 +115,44 @@ int _EXFUN(getlogin_r, (char *name, size_t namesize) ); #endif char * _EXFUN(getpass, (const char *__prompt)); int _EXFUN(getpagesize, (void)); -#if defined(__CYGWIN__) +#if __BSD_VISIBLE int _EXFUN(getpeereid, (int, uid_t *, gid_t *)); #endif pid_t _EXFUN(getpgid, (pid_t)); pid_t _EXFUN(getpgrp, (void )); pid_t _EXFUN(getpid, (void )); pid_t _EXFUN(getppid, (void )); -#if defined(__CYGWIN__) || defined(__rtems__) +#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 4 pid_t _EXFUN(getsid, (pid_t)); #endif #if !defined(__INSIDE_CYGWIN__) uid_t _EXFUN(getuid, (void )); #endif -#ifdef __CYGWIN__ +#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500) char * _EXFUN(getusershell, (void)); +#endif +#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200809) char * _EXFUN(getwd, (char *__buf )); +#endif +#if __BSD_VISIBLE int _EXFUN(iruserok, (unsigned long raddr, int superuser, const char *ruser, const char *luser)); #endif int _EXFUN(isatty, (int __fildes )); +#if __BSD_VISIBLE +int _EXFUN(issetugid, (void)); +#endif #if !defined(__INSIDE_CYGWIN__) int _EXFUN(lchown, (const char *__path, uid_t __owner, gid_t __group )); #endif int _EXFUN(link, (const char *__path1, const char *__path2 )); -#if __POSIX_VISIBLE >= 200809 || __BSD_VISIBLE || defined(__CYGWIN__) +#if __ATFILE_VISIBLE int _EXFUN(linkat, (int __dirfd1, const char *__path1, int __dirfd2, const char *__path2, int __flags )); #endif int _EXFUN(nice, (int __nice_value )); #if !defined(__INSIDE_CYGWIN__) off_t _EXFUN(lseek, (int __fildes, off_t __offset, int __whence )); #endif -#if defined(__SPU__) || defined(__CYGWIN__) +#if __MISC_VISIBLE || __XSI_VISIBLE >= 4 #define F_ULOCK 0 #define F_LOCK 1 #define F_TLOCK 2 @@ -137,41 +161,41 @@ int _EXFUN(lockf, (int __fd, int __cmd, off_t __len)); #endif long _EXFUN(pathconf, (const char *__path, int __name )); int _EXFUN(pause, (void )); -#ifdef __CYGWIN__ +#if __POSIX_VISIBLE >= 199506 int _EXFUN(pthread_atfork, (void (*)(void), void (*)(void), void (*)(void))); #endif int _EXFUN(pipe, (int __fildes[2] )); -#ifdef __CYGWIN__ +#if __GNU_VISIBLE int _EXFUN(pipe2, (int __fildes[2], int flags)); #endif ssize_t _EXFUN(pread, (int __fd, void *__buf, size_t __nbytes, off_t __offset)); ssize_t _EXFUN(pwrite, (int __fd, const void *__buf, size_t __nbytes, off_t __offset)); _READ_WRITE_RETURN_TYPE _EXFUN(read, (int __fd, void *__buf, size_t __nbyte )); -#if defined(__CYGWIN__) +#if __BSD_VISIBLE int _EXFUN(rresvport, (int *__alport)); int _EXFUN(revoke, (char *__path)); #endif int _EXFUN(rmdir, (const char *__path )); -#if defined(__CYGWIN__) +#if __BSD_VISIBLE int _EXFUN(ruserok, (const char *rhost, int superuser, const char *ruser, const char *luser)); #endif void * _EXFUN(sbrk, (ptrdiff_t __incr)); #if !defined(__INSIDE_CYGWIN__) -#if defined(__CYGWIN__) || defined(__rtems__) +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 int _EXFUN(setegid, (gid_t __gid )); int _EXFUN(seteuid, (uid_t __uid )); #endif int _EXFUN(setgid, (gid_t __gid )); #endif -#if defined(__CYGWIN__) +#if __BSD_VISIBLE int _EXFUN(setgroups, (int ngroups, const gid_t *grouplist )); #endif -#if __BSD_VISIBLE || (defined(_XOPEN_SOURCE) && __XSI_VISIBLE < 500) +#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500) int _EXFUN(sethostname, (const char *, size_t)); #endif int _EXFUN(setpgid, (pid_t __pid, pid_t __pgid )); int _EXFUN(setpgrp, (void )); -#if defined(__CYGWIN__) && !defined(__INSIDE_CYGWIN__) +#if (__BSD_VISIBLE || __XSI_VISIBLE >= 4) && !defined(__INSIDE_CYGWIN__) int _EXFUN(setregid, (gid_t __rgid, gid_t __egid)); int _EXFUN(setreuid, (uid_t __ruid, uid_t __euid)); #endif @@ -179,21 +203,25 @@ pid_t _EXFUN(setsid, (void )); #if !defined(__INSIDE_CYGWIN__) int _EXFUN(setuid, (uid_t __uid )); #endif -#if defined(__CYGWIN__) +#if __BSD_VISIBLE || (__XSI_VISIBLE && __XSI_VISIBLE < 500) void _EXFUN(setusershell, (void)); #endif unsigned _EXFUN(sleep, (unsigned int __seconds )); +#if __XSI_VISIBLE void _EXFUN(swab, (const void *__restrict, void *__restrict, ssize_t)); +#endif long _EXFUN(sysconf, (int __name )); pid_t _EXFUN(tcgetpgrp, (int __fildes )); int _EXFUN(tcsetpgrp, (int __fildes, pid_t __pgrp_id )); char * _EXFUN(ttyname, (int __fildes )); -#if defined(__CYGWIN__) || defined(__rtems__) -int _EXFUN(ttyname_r, (int, char *, size_t)); -#endif +int _EXFUN(ttyname_r, (int, char *, size_t)); int _EXFUN(unlink, (const char *__path )); +#if __XSI_VISIBLE >= 500 && __POSIX_VISIBLE < 200809 || __BSD_VISIBLE int _EXFUN(usleep, (useconds_t __useconds)); +#endif +#if __BSD_VISIBLE int _EXFUN(vhangup, (void )); +#endif _READ_WRITE_RETURN_TYPE _EXFUN(write, (int __fd, const void *__buf, size_t __nbyte )); #ifdef __CYGWIN__ @@ -207,9 +235,9 @@ int getopt(int, char * const [], const char *); extern int optreset; /* getopt(3) external variable */ #endif -#ifndef _POSIX_SOURCE +#if __BSD_VISIBLE || (__XSI_VISIBLE >= 4 && __POSIX_VISIBLE < 200809) pid_t _EXFUN(vfork, (void )); -#endif /* _POSIX_SOURCE */ +#endif #ifdef _COMPILING_NEWLIB /* Provide prototypes for most of the _ names that are @@ -230,36 +258,45 @@ _READ_WRITE_RETURN_TYPE _EXFUN(_write, (int __fd, const void *__buf, size_t __nb int _EXFUN(_execve, (const char *__path, char * const __argv[], char * const __envp[] )); #endif -#if defined(__CYGWIN__) || defined(__rtems__) || defined(__aarch64__) || defined (__arm__) || defined(__sh__) || defined(__SPU__) #if !defined(__INSIDE_CYGWIN__) +#if __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 500 int _EXFUN(ftruncate, (int __fd, off_t __length)); +#endif +#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 500 int _EXFUN(truncate, (const char *, off_t __length)); #endif #endif -#if defined(__CYGWIN__) || defined(__rtems__) +#if __BSD_VISIBLE || __POSIX_VISIBLE < 200112 int _EXFUN(getdtablesize, (void)); -int _EXFUN(setdtablesize, (int)); +#endif +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE >= 500 useconds_t _EXFUN(ualarm, (useconds_t __useconds, useconds_t __interval)); +#endif + +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 500 #if !(defined (_WINSOCK_H) || defined (_WINSOCKAPI_) || defined (__USE_W32_SOCKETS)) /* winsock[2].h defines as __stdcall, and with int as 2nd arg */ int _EXFUN(gethostname, (char *__name, size_t __len)); #endif -char * _EXFUN(mktemp, (char *)); #endif -#if defined(__CYGWIN__) || defined(__SPU__) || defined(__rtems__) +#if __MISC_VISIBLE +int _EXFUN(setdtablesize, (int)); +#endif + +#if __BSD_VISIBLE || __XSI_VISIBLE >= 500 void _EXFUN(sync, (void)); #endif +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE >= 4 ssize_t _EXFUN(readlink, (const char *__restrict __path, char *__restrict __buf, size_t __buflen)); -#if __POSIX_VISIBLE >= 200809 || __BSD_VISIBLE || defined(__CYGWIN__) +int _EXFUN(symlink, (const char *__name1, const char *__name2)); +#endif +#if __ATFILE_VISIBLE ssize_t _EXFUN(readlinkat, (int __dirfd1, const char *__restrict __path, char *__restrict __buf, size_t __buflen)); -#endif -int _EXFUN(symlink, (const char *__name1, const char *__name2)); -#if __POSIX_VISIBLE >= 200809 || __BSD_VISIBLE || defined(__CYGWIN__) int _EXFUN(symlinkat, (const char *, int, const char *)); int _EXFUN(unlinkat, (int, const char *, int)); #endif @@ -422,6 +459,22 @@ int _EXFUN(unlinkat, (int, const char *, int)); #define _SC_THREAD_ROBUST_PRIO_INHERIT 122 #define _SC_THREAD_ROBUST_PRIO_PROTECT 123 #define _SC_XOPEN_UUCP 124 +#define _SC_LEVEL1_ICACHE_SIZE 125 +#define _SC_LEVEL1_ICACHE_ASSOC 126 +#define _SC_LEVEL1_ICACHE_LINESIZE 127 +#define _SC_LEVEL1_DCACHE_SIZE 128 +#define _SC_LEVEL1_DCACHE_ASSOC 129 +#define _SC_LEVEL1_DCACHE_LINESIZE 130 +#define _SC_LEVEL2_CACHE_SIZE 131 +#define _SC_LEVEL2_CACHE_ASSOC 132 +#define _SC_LEVEL2_CACHE_LINESIZE 133 +#define _SC_LEVEL3_CACHE_SIZE 134 +#define _SC_LEVEL3_CACHE_ASSOC 135 +#define _SC_LEVEL3_CACHE_LINESIZE 136 +#define _SC_LEVEL4_CACHE_SIZE 137 +#define _SC_LEVEL4_CACHE_ASSOC 138 +#define _SC_LEVEL4_CACHE_LINESIZE 139 +#define _SC_POSIX_26_VERSION 140 /* * pathconf values per IEEE Std 1003.1, 2008 Edition @@ -453,6 +506,7 @@ int _EXFUN(unlinkat, (int, const char *, int)); #define _PC_POSIX_PERMISSIONS 90 /* Ask for full POSIX permission support including uid/gid settings. */ #define _PC_POSIX_SECURITY 91 +#define _PC_CASE_INSENSITIVE 92 #endif /* diff --git a/libc/xtensa-lx106-elf/include/sys/wait.h b/libc/xtensa-lx106-elf/include/sys/wait.h index 73fe372..f17e53f 100644 --- a/libc/xtensa-lx106-elf/include/sys/wait.h +++ b/libc/xtensa-lx106-elf/include/sys/wait.h @@ -11,7 +11,7 @@ extern "C" { #define WUNTRACED 2 /* A status looks like: - <2 bytes info> <2 bytes code> + <1 byte info> <1 byte code> == 0, child has exited, info is the exit value == 1..7e, child has exited, info is the signal number. diff --git a/libc/xtensa-lx106-elf/include/tar.h b/libc/xtensa-lx106-elf/include/tar.h index 07b06dd..36437fc 100644 --- a/libc/xtensa-lx106-elf/include/tar.h +++ b/libc/xtensa-lx106-elf/include/tar.h @@ -5,6 +5,8 @@ #ifndef _TAR_H #define _TAR_H +#include + /* General definitions */ #define TMAGIC "ustar" /* ustar plus null byte. */ #define TMAGLEN 6 /* Length of the above. */ @@ -25,7 +27,9 @@ /* Mode field bit definitions (octal) */ #define TSUID 04000 /* Set UID on execution. */ #define TSGID 02000 /* Set GID on execution. */ +#if __XSI_VISIBLE || __POSIX_VISIBLE < 200112 #define TSVTX 01000 /* On directories, restricted deletion flag. */ +#endif #define TUREAD 00400 /* Read by owner. */ #define TUWRITE 00200 /* Write by owner. */ #define TUEXEC 00100 /* Execute/search by owner. */ diff --git a/libc/xtensa-lx106-elf/include/tgmath.h b/libc/xtensa-lx106-elf/include/tgmath.h index f9c8311..97dc50e 100644 --- a/libc/xtensa-lx106-elf/include/tgmath.h +++ b/libc/xtensa-lx106-elf/include/tgmath.h @@ -79,7 +79,7 @@ __tg_type3(__e1, __e2, __e3, long double _Complex) || \ __tg_type3(__e1, __e2, __e3, __typeof__(_Complex_I))) -#ifdef _LDBL_EQ_DBL +#if defined (_LDBL_EQ_DBL) || defined (__CYGWIN__) #define __tg_impl_simple(x, y, z, fn, fnf, fnl, ...) \ __builtin_choose_expr(__tg_type_corr(x, y, z, long double), \ fnl(__VA_ARGS__), __builtin_choose_expr( \ @@ -161,9 +161,10 @@ #define lround(__x) __tg_simple(__x, lround) #define nearbyint(__x) __tg_simple(__x, nearbyint) #define nextafter(__x, __y) __tg_simple2(__x, __y, nextafter) -/* not yet implemented even for _LDBL_EQ_DBL platforms +/* not yet implemented even for _LDBL_EQ_DBL platforms */ +#ifdef __CYGWIN__ #define nexttoward(__x, __y) __tg_simplev(__x, nexttoward, __x, __y) -*/ +#endif #define remainder(__x, __y) __tg_simple2(__x, __y, remainder) #define remquo(__x, __y, __z) __tg_impl_simple(__x, __x, __y, remquo, remquof, \ remquol, __x, __y, __z) diff --git a/libc/xtensa-lx106-elf/include/threads.h b/libc/xtensa-lx106-elf/include/threads.h new file mode 100644 index 0000000..9fb08b0 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/threads.h @@ -0,0 +1,93 @@ +/*- + * Copyright (c) 2011 Ed Schouten + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _THREADS_H_ +#define _THREADS_H_ + +#include +#include + +typedef void (*tss_dtor_t)(void *); +typedef int (*thrd_start_t)(void *); + +enum { + mtx_plain = 0x1, + mtx_recursive = 0x2, + mtx_timed = 0x4 +}; + +enum { + thrd_busy = 1, + thrd_error = 2, + thrd_nomem = 3, + thrd_success = 4, + thrd_timedout = 5 +}; + +#if !defined(__cplusplus) || __cplusplus < 201103L +#define thread_local _Thread_local +#endif + +__BEGIN_DECLS +void call_once(once_flag *, void (*)(void)); +int cnd_broadcast(cnd_t *); +void cnd_destroy(cnd_t *); +int cnd_init(cnd_t *); +int cnd_signal(cnd_t *); +int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx, + const struct timespec *__restrict) + __requires_exclusive(*__mtx); +int cnd_wait(cnd_t *, mtx_t *__mtx) + __requires_exclusive(*__mtx); +void mtx_destroy(mtx_t *__mtx) + __requires_unlocked(*__mtx); +int mtx_init(mtx_t *__mtx, int) + __requires_unlocked(*__mtx); +int mtx_lock(mtx_t *__mtx) + __locks_exclusive(*__mtx); +int mtx_timedlock(mtx_t *__restrict __mtx, + const struct timespec *__restrict) + __trylocks_exclusive(thrd_success, *__mtx); +int mtx_trylock(mtx_t *__mtx) + __trylocks_exclusive(thrd_success, *__mtx); +int mtx_unlock(mtx_t *__mtx) + __unlocks(*__mtx); +int thrd_create(thrd_t *, thrd_start_t, void *); +thrd_t thrd_current(void); +int thrd_detach(thrd_t); +int thrd_equal(thrd_t, thrd_t); +_Noreturn void + thrd_exit(int); +int thrd_join(thrd_t, int *); +int thrd_sleep(const struct timespec *, struct timespec *); +void thrd_yield(void); +int tss_create(tss_t *, tss_dtor_t); +void tss_delete(tss_t); +void * tss_get(tss_t); +int tss_set(tss_t, void *); +__END_DECLS + +#endif /* !_THREADS_H_ */ diff --git a/libc/xtensa-lx106-elf/include/time.h b/libc/xtensa-lx106-elf/include/time.h index d7b6612..8806b98 100644 --- a/libc/xtensa-lx106-elf/include/time.h +++ b/libc/xtensa-lx106-elf/include/time.h @@ -8,6 +8,7 @@ #define _TIME_H_ #include "_ansi.h" +#include #include #define __need_size_t @@ -25,6 +26,11 @@ #define CLK_TCK CLOCKS_PER_SEC #include +#include + +#if __POSIX_VISIBLE >= 200809 +#include +#endif _BEGIN_STD_C @@ -61,6 +67,12 @@ size_t _EXFUN(strftime, (char *__restrict _s, size_t _maxsize, const char *__restrict _fmt, const struct tm *__restrict _t)); +#if __POSIX_VISIBLE >= 200809 +extern size_t strftime_l (char *__restrict _s, size_t _maxsize, + const char *__restrict _fmt, + const struct tm *__restrict _t, locale_t _l); +#endif + char *_EXFUN(asctime_r, (const struct tm *__restrict, char *__restrict)); char *_EXFUN(ctime_r, (const time_t *, char *)); @@ -75,11 +87,19 @@ _END_STD_C extern "C" { #endif -#ifndef __STRICT_ANSI__ +#if __XSI_VISIBLE char *_EXFUN(strptime, (const char *__restrict, const char *__restrict, struct tm *__restrict)); +#endif +#if __GNU_VISIBLE +char *strptime_l (const char *__restrict, const char *__restrict, + struct tm *__restrict, locale_t); +#endif + +#if __POSIX_VISIBLE _VOID _EXFUN(tzset, (_VOID)); +#endif _VOID _EXFUN(_tzset_r, (struct _reent *)); typedef struct __tzrule_struct @@ -105,6 +125,7 @@ __tzinfo_type *_EXFUN (__gettzinfo, (_VOID)); /* getdate functions */ #ifdef HAVE_GETDATE +#if __XSI_VISIBLE >= 4 #ifndef _REENT_ONLY #define getdate_err (*__getdate_err()) int *_EXFUN(__getdate_err,(_VOID)); @@ -120,21 +141,27 @@ struct tm * _EXFUN(getdate, (const char *)); 7 there is no line in the template that matches the input, 8 invalid input specification */ #endif /* !_REENT_ONLY */ +#endif /* __XSI_VISIBLE >= 4 */ +#if __GNU_VISIBLE /* getdate_r returns the error code as above */ int _EXFUN(getdate_r, (const char *, struct tm *)); +#endif /* __GNU_VISIBLE */ #endif /* HAVE_GETDATE */ /* defines for the opengroup specifications Derived from Issue 1 of the SVID. */ +#if __SVID_VISIBLE || __XSI_VISIBLE extern __IMPORT long _timezone; extern __IMPORT int _daylight; +#endif +#if __POSIX_VISIBLE extern __IMPORT char *_tzname[2]; /* POSIX defines the external tzname being defined in time.h */ #ifndef tzname #define tzname _tzname #endif -#endif /* !__STRICT_ANSI__ */ +#endif /* __POSIX_VISIBLE */ #ifdef __cplusplus } diff --git a/libc/xtensa-lx106-elf/include/wchar.h b/libc/xtensa-lx106-elf/include/wchar.h index 810a6c0..6b4eff9 100644 --- a/libc/xtensa-lx106-elf/include/wchar.h +++ b/libc/xtensa-lx106-elf/include/wchar.h @@ -11,15 +11,32 @@ #define __need_NULL #include -#define __need___va_list -#include - /* For _mbstate_t definition. */ #include #include /* For __STDC_ISO_10646__ */ #include +/* typedef only __gnuc_va_list, used throughout the header */ +#define __need___va_list +#include + +/* typedef va_list only when required */ +#if __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE +#ifdef __GNUC__ +#ifndef _VA_LIST_DEFINED +typedef __gnuc_va_list va_list; +#define _VA_LIST_DEFINED +#endif +#else /* !__GNUC__ */ +#include +#endif +#endif /* __POSIX_VISIBLE >= 200809 || __XSI_VISIBLE */ + +#if __XSI_VISIBLE /* && __XSI_VISIBLE < 800 */ && !__GNU_VISIBLE +#include +#endif + #ifndef WEOF # define WEOF ((wint_t)-1) #endif @@ -46,10 +63,19 @@ #endif #endif +#if __POSIX_VISIBLE >= 200809 +#include +#endif + _BEGIN_STD_C +#if __POSIX_VISIBLE >= 200809 || _XSI_VISIBLE /* As in stdio.h, defines __FILE. */ +#if !defined(__FILE_defined) typedef __FILE FILE; +# define __FILE_defined +#endif +#endif /* As required by POSIX.1-2008, declare tm as incomplete type. The actual definition is in time.h. */ @@ -68,8 +94,10 @@ size_t _EXFUN(mbrtowc, (wchar_t *__restrict, const char *__restrict, size_t, size_t _EXFUN(_mbrtowc_r, (struct _reent *, wchar_t * , const char * , size_t, mbstate_t *)); int _EXFUN(mbsinit, (const mbstate_t *)); +#if __POSIX_VISIBLE >= 200809 size_t _EXFUN(mbsnrtowcs, (wchar_t *__restrict, const char **__restrict, size_t, size_t, mbstate_t *__restrict)); +#endif size_t _EXFUN(_mbsnrtowcs_r, (struct _reent *, wchar_t * , const char ** , size_t, size_t, mbstate_t *)); size_t _EXFUN(mbsrtowcs, (wchar_t *__restrict, const char **__restrict, size_t, @@ -77,39 +105,53 @@ size_t _EXFUN(mbsrtowcs, (wchar_t *__restrict, const char **__restrict, size_t, size_t _EXFUN(_mbsrtowcs_r, (struct _reent *, wchar_t * , const char ** , size_t, mbstate_t *)); size_t _EXFUN(wcrtomb, (char *__restrict, wchar_t, mbstate_t *__restrict)); size_t _EXFUN(_wcrtomb_r, (struct _reent *, char * , wchar_t, mbstate_t *)); +#if __POSIX_VISIBLE >= 200809 size_t _EXFUN(wcsnrtombs, (char *__restrict, const wchar_t **__restrict, size_t, size_t, mbstate_t *__restrict)); +#endif size_t _EXFUN(_wcsnrtombs_r, (struct _reent *, char * , const wchar_t ** , size_t, size_t, mbstate_t *)); size_t _EXFUN(wcsrtombs, (char *__restrict, const wchar_t **__restrict, size_t, mbstate_t *__restrict)); size_t _EXFUN(_wcsrtombs_r, (struct _reent *, char * , const wchar_t ** , size_t, mbstate_t *)); +#if __POSIX_VISIBLE >= 200809 int _EXFUN(wcscasecmp, (const wchar_t *, const wchar_t *)); +#endif wchar_t *_EXFUN(wcscat, (wchar_t *__restrict, const wchar_t *__restrict)); wchar_t *_EXFUN(wcschr, (const wchar_t *, wchar_t)); int _EXFUN(wcscmp, (const wchar_t *, const wchar_t *)); int _EXFUN(wcscoll, (const wchar_t *, const wchar_t *)); wchar_t *_EXFUN(wcscpy, (wchar_t *__restrict, const wchar_t *__restrict)); +#if __POSIX_VISIBLE >= 200809 wchar_t *_EXFUN(wcpcpy, (wchar_t *__restrict, const wchar_t *__restrict)); wchar_t *_EXFUN(wcsdup, (const wchar_t *)); +#endif wchar_t *_EXFUN(_wcsdup_r, (struct _reent *, const wchar_t * )); size_t _EXFUN(wcscspn, (const wchar_t *, const wchar_t *)); size_t _EXFUN(wcsftime, (wchar_t *__restrict, size_t, const wchar_t *__restrict, const struct tm *__restrict)); +#if __GNU_VISIBLE +size_t wcsftime_l (wchar_t *__restrict, size_t, const wchar_t *__restrict, + const struct tm *__restrict, locale_t); +#endif size_t _EXFUN(wcslcat, (wchar_t *, const wchar_t *, size_t)); size_t _EXFUN(wcslcpy, (wchar_t *, const wchar_t *, size_t)); size_t _EXFUN(wcslen, (const wchar_t *)); +#if __POSIX_VISIBLE >= 200809 int _EXFUN(wcsncasecmp, (const wchar_t *, const wchar_t *, size_t)); +#endif wchar_t *_EXFUN(wcsncat, (wchar_t *__restrict, const wchar_t *__restrict, size_t)); int _EXFUN(wcsncmp, (const wchar_t *, const wchar_t *, size_t)); wchar_t *_EXFUN(wcsncpy, (wchar_t *__restrict, const wchar_t *__restrict, size_t)); +#if __POSIX_VISIBLE >= 200809 wchar_t *_EXFUN(wcpncpy, (wchar_t *__restrict, const wchar_t *__restrict, size_t)); size_t _EXFUN(wcsnlen, (const wchar_t *, size_t)); +#endif wchar_t *_EXFUN(wcspbrk, (const wchar_t *, const wchar_t *)); wchar_t *_EXFUN(wcsrchr, (const wchar_t *, wchar_t)); size_t _EXFUN(wcsspn, (const wchar_t *, const wchar_t *)); @@ -119,15 +161,29 @@ wchar_t *_EXFUN(wcstok, (wchar_t *__restrict, const wchar_t *__restrict, wchar_t **__restrict)); double _EXFUN(wcstod, (const wchar_t *__restrict, wchar_t **__restrict)); double _EXFUN(_wcstod_r, (struct _reent *, const wchar_t *, wchar_t **)); +#if __ISO_C_VISIBLE >= 1999 float _EXFUN(wcstof, (const wchar_t *__restrict, wchar_t **__restrict)); +#endif float _EXFUN(_wcstof_r, (struct _reent *, const wchar_t *, wchar_t **)); #ifdef _LDBL_EQ_DBL long double _EXFUN(wcstold, (const wchar_t *, wchar_t **)); #endif /* _LDBL_EQ_DBL */ +#if __XSI_VISIBLE int _EXFUN(wcswidth, (const wchar_t *, size_t)); +#endif size_t _EXFUN(wcsxfrm, (wchar_t *__restrict, const wchar_t *__restrict, size_t)); +#if __POSIX_VISIBLE >= 200809 +extern int wcscasecmp_l (const wchar_t *, const wchar_t *, locale_t); +extern int wcsncasecmp_l (const wchar_t *, const wchar_t *, size_t, locale_t); +extern int wcscoll_l (const wchar_t *, const wchar_t *, locale_t); +extern size_t wcsxfrm_l (wchar_t *__restrict, const wchar_t *__restrict, size_t, + locale_t); +#endif + +#if __XSI_VISIBLE int _EXFUN(wcwidth, (const wchar_t)); +#endif wchar_t *_EXFUN(wmemchr, (const wchar_t *, wchar_t, size_t)); int _EXFUN(wmemcmp, (const wchar_t *, const wchar_t *, size_t)); wchar_t *_EXFUN(wmemcpy, (wchar_t *__restrict, const wchar_t *__restrict, @@ -136,26 +192,44 @@ wchar_t *_EXFUN(wmemmove, (wchar_t *, const wchar_t *, size_t)); wchar_t *_EXFUN(wmemset, (wchar_t *, wchar_t, size_t)); long _EXFUN(wcstol, (const wchar_t *__restrict, wchar_t **__restrict, int)); +#if __ISO_C_VISIBLE >= 1999 long long _EXFUN(wcstoll, (const wchar_t *__restrict, wchar_t **__restrict, int)); +#endif unsigned long _EXFUN(wcstoul, (const wchar_t *__restrict, wchar_t **__restrict, int)); +#if __ISO_C_VISIBLE >= 1999 unsigned long long _EXFUN(wcstoull, (const wchar_t *__restrict, wchar_t **__restrict, int)); +#endif long _EXFUN(_wcstol_r, (struct _reent *, const wchar_t *, wchar_t **, int)); long long _EXFUN(_wcstoll_r, (struct _reent *, const wchar_t *, wchar_t **, int)); unsigned long _EXFUN(_wcstoul_r, (struct _reent *, const wchar_t *, wchar_t **, int)); unsigned long long _EXFUN(_wcstoull_r, (struct _reent *, const wchar_t *, wchar_t **, int)); -/* On platforms where long double equals double. */ -#ifdef _LDBL_EQ_DBL +#if __ISO_C_VISIBLE >= 1999 long double _EXFUN(wcstold, (const wchar_t *, wchar_t **)); -#endif /* _LDBL_EQ_DBL */ +#endif + +#if __GNU_VISIBLE +long wcstol_l (const wchar_t *__restrict, wchar_t **__restrict, int, locale_t); +long long wcstoll_l (const wchar_t *__restrict, wchar_t **__restrict, int, + locale_t); +unsigned long wcstoul_l (const wchar_t *__restrict, wchar_t **__restrict, int, + locale_t); +unsigned long long wcstoull_l (const wchar_t *__restrict, wchar_t **__restrict, + int, locale_t); +double wcstod_l (const wchar_t *, wchar_t **, locale_t); +float wcstof_l (const wchar_t *, wchar_t **, locale_t); +long double wcstold_l (const wchar_t *, wchar_t **, locale_t); +#endif wint_t _EXFUN(fgetwc, (__FILE *)); wchar_t *_EXFUN(fgetws, (wchar_t *__restrict, int, __FILE *__restrict)); wint_t _EXFUN(fputwc, (wchar_t, __FILE *)); int _EXFUN(fputws, (const wchar_t *__restrict, __FILE *__restrict)); +#if __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE >= 500 int _EXFUN (fwide, (__FILE *, int)); +#endif wint_t _EXFUN (getwc, (__FILE *)); wint_t _EXFUN (getwchar, (void)); wint_t _EXFUN(putwc, (wchar_t, __FILE *)); @@ -192,7 +266,9 @@ wint_t _EXFUN(putwc_unlocked, (wchar_t, __FILE *)); wint_t _EXFUN(putwchar_unlocked, (wchar_t)); #endif +#if __POSIX_VISIBLE >= 200809 __FILE *_EXFUN (open_wmemstream, (wchar_t **, size_t *)); +#endif __FILE *_EXFUN (_open_wmemstream_r, (struct _reent *, wchar_t **, size_t *)); #ifndef __VALIST @@ -203,6 +279,7 @@ __FILE *_EXFUN (_open_wmemstream_r, (struct _reent *, wchar_t **, size_t *)); #endif #endif +#if __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE >= 500 int _EXFUN(fwprintf, (__FILE *__restrict, const wchar_t *__restrict, ...)); int _EXFUN(swprintf, (wchar_t *__restrict, size_t, const wchar_t *__restrict, ...)); @@ -212,6 +289,7 @@ int _EXFUN(vswprintf, (wchar_t *__restrict, size_t, const wchar_t *__restrict, __VALIST)); int _EXFUN(vwprintf, (const wchar_t *__restrict, __VALIST)); int _EXFUN(wprintf, (const wchar_t *__restrict, ...)); +#endif int _EXFUN(_fwprintf_r, (struct _reent *, __FILE *, const wchar_t *, ...)); int _EXFUN(_swprintf_r, (struct _reent *, wchar_t *, size_t, const wchar_t *, ...)); @@ -220,6 +298,7 @@ int _EXFUN(_vswprintf_r, (struct _reent *, wchar_t *, size_t, const wchar_t *, _ int _EXFUN(_vwprintf_r, (struct _reent *, const wchar_t *, __VALIST)); int _EXFUN(_wprintf_r, (struct _reent *, const wchar_t *, ...)); +#if __ISO_C_VISIBLE >= 1999 || __XSI_VISIBLE >= 500 int _EXFUN(fwscanf, (__FILE *__restrict, const wchar_t *__restrict, ...)); int _EXFUN(swscanf, (const wchar_t *__restrict, const wchar_t *__restrict, ...)); @@ -229,6 +308,7 @@ int _EXFUN(vswscanf, (const wchar_t *__restrict, const wchar_t *__restrict, __VALIST)); int _EXFUN(vwscanf, (const wchar_t *__restrict, __VALIST)); int _EXFUN(wscanf, (const wchar_t *__restrict, ...)); +#endif int _EXFUN(_fwscanf_r, (struct _reent *, __FILE *, const wchar_t *, ...)); int _EXFUN(_swscanf_r, (struct _reent *, const wchar_t *, const wchar_t *, ...)); diff --git a/libc/xtensa-lx106-elf/include/wctype.h b/libc/xtensa-lx106-elf/include/wctype.h index c72c9de..3d36d5a 100644 --- a/libc/xtensa-lx106-elf/include/wctype.h +++ b/libc/xtensa-lx106-elf/include/wctype.h @@ -7,6 +7,10 @@ #define __need_wint_t #include +#if __POSIX_VISIBLE >= 200809 +#include +#endif + #ifndef WEOF # define WEOF ((wint_t)-1) #endif @@ -25,7 +29,9 @@ typedef int wctrans_t; int _EXFUN(iswalpha, (wint_t)); int _EXFUN(iswalnum, (wint_t)); +#if __ISO_C_VISIBLE >= 1999 int _EXFUN(iswblank, (wint_t)); +#endif int _EXFUN(iswcntrl, (wint_t)); int _EXFUN(iswctype, (wint_t, wctype_t)); int _EXFUN(iswdigit, (wint_t)); @@ -42,6 +48,27 @@ wint_t _EXFUN(towlower, (wint_t)); wctrans_t _EXFUN(wctrans, (const char *)); wctype_t _EXFUN(wctype, (const char *)); +#if __POSIX_VISIBLE >= 200809 +extern int iswalpha_l (wint_t, locale_t); +extern int iswalnum_l (wint_t, locale_t); +extern int iswblank_l (wint_t, locale_t); +extern int iswcntrl_l (wint_t, locale_t); +extern int iswctype_l (wint_t, wctype_t, locale_t); +extern int iswdigit_l (wint_t, locale_t); +extern int iswgraph_l (wint_t, locale_t); +extern int iswlower_l (wint_t, locale_t); +extern int iswprint_l (wint_t, locale_t); +extern int iswpunct_l (wint_t, locale_t); +extern int iswspace_l (wint_t, locale_t); +extern int iswupper_l (wint_t, locale_t); +extern int iswxdigit_l (wint_t, locale_t); +extern wint_t towctrans_l (wint_t, wctrans_t, locale_t); +extern wint_t towupper_l (wint_t, locale_t); +extern wint_t towlower_l (wint_t, locale_t); +extern wctrans_t wctrans_l (const char *, locale_t); +extern wctype_t wctype_l (const char *, locale_t); +#endif + _END_STD_C #endif /* _WCTYPE_H_ */ diff --git a/libc/xtensa-lx106-elf/include/xlocale.h b/libc/xtensa-lx106-elf/include/xlocale.h new file mode 100644 index 0000000..f955426 --- /dev/null +++ b/libc/xtensa-lx106-elf/include/xlocale.h @@ -0,0 +1,12 @@ +/* Definition of opaque POSIX-1.2008 type locale_t for userspace. */ + +#ifndef _XLOCALE_H +#define _XLOCALE_H + +#include +#include + +struct __locale_t; +typedef struct __locale_t *locale_t; + +#endif /* _XLOCALE_H */ diff --git a/libc/xtensa-lx106-elf/lib/crt0.o b/libc/xtensa-lx106-elf/lib/crt0.o index 7d17e27..efc11bc 100644 Binary files a/libc/xtensa-lx106-elf/lib/crt0.o and b/libc/xtensa-lx106-elf/lib/crt0.o differ diff --git a/libc/xtensa-lx106-elf/lib/libc.a b/libc/xtensa-lx106-elf/lib/libc.a index a43b5ed..2c1132e 100644 Binary files a/libc/xtensa-lx106-elf/lib/libc.a and b/libc/xtensa-lx106-elf/lib/libc.a differ diff --git a/libc/xtensa-lx106-elf/lib/libg.a b/libc/xtensa-lx106-elf/lib/libg.a index 4d3d50a..2c1132e 100644 Binary files a/libc/xtensa-lx106-elf/lib/libg.a and b/libc/xtensa-lx106-elf/lib/libg.a differ diff --git a/libc/xtensa-lx106-elf/lib/libm.a b/libc/xtensa-lx106-elf/lib/libm.a index 2e9a859..2285786 100644 Binary files a/libc/xtensa-lx106-elf/lib/libm.a and b/libc/xtensa-lx106-elf/lib/libm.a differ diff --git a/lwip/component.mk b/lwip/component.mk index 1bbe21c..ea35d05 100644 --- a/lwip/component.mk +++ b/lwip/component.mk @@ -1,14 +1,12 @@ # Component makefile for LWIP LWIP_DIR = $(lwip_ROOT)lwip/src/ -INC_DIRS += $(LWIP_DIR)include $(ROOT)lwip/include $(lwip_ROOT)include $(LWIP_DIR)include/posix $(LWIP_DIR)include/ipv4 $(LWIP_DIR)include/ipv4/lwip $(LWIP_DIR)include/lwip +INC_DIRS += $(LWIP_DIR)include $(ROOT)lwip/include $(lwip_ROOT)include $(LWIP_DIR)include/compat/posix $(LWIP_DIR)include/ipv4 $(LWIP_DIR)include/ipv4/lwip $(LWIP_DIR)include/lwip # args for passing into compile rule generation lwip_INC_DIR = # all in INC_DIRS, needed for normal operation -lwip_SRC_DIR = $(lwip_ROOT) $(LWIP_DIR)api $(LWIP_DIR)core $(LWIP_DIR)core/ipv4 $(LWIP_DIR)netif - -# LWIP 1.4.1 generates a single warning so we need to disable -Werror when building it -lwip_CFLAGS = $(CFLAGS) -Wno-address +lwip_SRC_DIR = $(lwip_ROOT) $(LWIP_DIR)api $(LWIP_DIR)core $(LWIP_DIR)core/ipv4 $(LWIP_DIR)core/ipv6 $(LWIP_DIR)netif +lwip_SRC_DIR += $(LWIP_DIR)apps/* $(eval $(call component_compile_rules,lwip)) diff --git a/lwip/esp_interface.c b/lwip/esp_interface.c index 6f37b5a..77ad177 100644 --- a/lwip/esp_interface.c +++ b/lwip/esp_interface.c @@ -37,6 +37,7 @@ * Original Author: Simon Goldschmidt * Modified by Angus Gratton based on work by @kadamski/Espressif via esp-lwip project. */ +#include #include "lwip/opt.h" #include "lwip/def.h" @@ -44,77 +45,259 @@ #include "lwip/pbuf.h" #include #include +#include "lwip/ip.h" +#include "lwip/ethip6.h" +#include "lwip/priv/tcp_priv.h" #include "netif/etharp.h" +#include "sysparam.h" +#include "netif/ppp/pppoe.h" +#include "FreeRTOS.h" +#include "task.h" /* declared in libnet80211.a */ int8_t sdk_ieee80211_output_pbuf(struct netif *ifp, struct pbuf* pb); +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + * for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ + /* set MAC hardware address length */ + netif->hwaddr_len = ETHARP_HWADDR_LEN; + + /* maximum transfer unit */ + netif->mtu = 1500; + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6; + + /* Do whatever else is needed to initialize interface. */ +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become available since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ +#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) static err_t low_level_output(struct netif *netif, struct pbuf *p) { - struct pbuf *q; + /* + * Note the pbuf reference count is generally one here, but not always. For + * example a buffer that had been queued by etharp_query() would have had + * its reference count increased to two, and the caller will free it on that + * return path. + */ - for(q = p; q != NULL; q = q->next) { - sdk_ieee80211_output_pbuf(netif, q); - } + /* If the pbuf does not have contiguous data, or there is not enough room + * for the link layer header, or there are multiple pbufs in the chain then + * clone a pbuf to output. */ + if ((p->type_internal & PBUF_TYPE_FLAG_STRUCT_DATA_CONTIGUOUS) == 0 || + (u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF + PBUF_LINK_ENCAPSULATION_HLEN || + p->next) { + struct pbuf *q = pbuf_clone(PBUF_RAW_TX, PBUF_RAM, p); + if (q == NULL) { + return ERR_MEM; + } + sdk_ieee80211_output_pbuf(netif, q); + /* The sdk will pbuf_ref the pbuf before returning and free it later + * when it has been sent so free the link to it here. */ + pbuf_free(q); + } else { + /* The SDK modifies the eth_hdr, well the first 12 bytes of it at least, + * but otherwise leaves the payload unmodified so it can be reused by + * the caller. The only paths that appear to reuse the pbuf are in + * tcp_out for re-transmission of TCP segments, and these paths check + * that the number of references has returned to one before reusing the + * pbuf. + */ + sdk_ieee80211_output_pbuf(netif, p); + } - LINK_STATS_INC(link.xmit); - - return ERR_OK; + LINK_STATS_INC(link.xmit); + return ERR_OK; } -err_t ethernetif_init(struct netif *netif) +/** + * Keep account of the number the PP RX pool buffers being used in lwip, + * to help make decision about the number of OOSEQ buffers to maintain etc. + */ +volatile uint32_t pp_rx_pool_usage; + +/* Support for recycling a pbuf from the sdk rx pool, and accounting for the + * number of these used in lwip. */ +void pp_recycle_rx_pbuf(struct pbuf *p) { - LWIP_ASSERT("netif != NULL", (netif != NULL)); - -#if LWIP_NETIF_HOSTNAME - /* Initialize interface hostname */ - netif->hostname = "lwip"; -#endif /* LWIP_NETIF_HOSTNAME */ - - /* - * Initialize the snmp variables and counters inside the struct netif. - * The last argument should be replaced with your link speed, in units - * of bits per second. - */ - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); - - // don't touch netif->state here, the field is used internally in the ESP SDK layers - netif->name[0] = 'e'; - netif->name[1] = 'n'; - netif->output = etharp_output; - netif->linkoutput = low_level_output; - - /* low_level_init components */ - netif->hwaddr_len = 6; - /* hwaddr seems to be set elsewhere, or (more likely) is set on tx by MAC layer */ - netif->mtu = 1500; - netif->flags = NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; - - return ERR_OK; + LWIP_ASSERT("expected esf_buf", p->esf_buf); + sdk_system_pp_recycle_rx_pkt(p->esf_buf); + taskENTER_CRITICAL(); + LWIP_ASSERT("pp_rx_pool_usage underflow", pp_rx_pool_usage > 0); + pp_rx_pool_usage--; + taskEXIT_CRITICAL(); } +/* Set to true to copy the rx pbufs on input and free them. The pp rx buffer + * pool is limited so this allows a large number at the expense of memory. + */ + +#define COPY_PP_RX_PBUFS 0 + +#if TCP_QUEUE_OOSEQ + +/* Return the number of ooseq bytes that can be retained given the current + * size 'n'. */ +size_t ooseq_bytes_limit(struct tcp_pcb *pcb) +{ +#if COPY_PP_RX_PBUFS + struct tcp_seg *ooseq = pcb->ooseq; + size_t ooseq_blen = 0; + for (; ooseq != NULL; ooseq = ooseq->next) { + struct pbuf *p = ooseq->p; + ooseq_blen += p->tot_len; + } + + size_t free = xPortGetFreeHeapSize(); + ssize_t target = ((ssize_t)free - 8000) + ooseq_blen; + + if (target < 0) { + target = 0; + } + + return target; +#else + /* The pool is pre-allocated so there is no need to look at the dynamic + * memory usage, just consider the number of them below. */ + return 8000; +#endif +} + +/* Return the number of ooseq pbufs that can be retained given the current + * size 'n'. */ +size_t ooseq_pbufs_limit(struct tcp_pcb *pcb) +{ + struct tcp_seg *ooseq = pcb->ooseq; + size_t ooseq_qlen = 0; + for (; ooseq != NULL; ooseq = ooseq->next) { + struct pbuf *p = ooseq->p; + ooseq_qlen += pbuf_clen(p); + } + +#if COPY_PP_RX_PBUFS + /* More likely memory limited, but set some limit. */ + ssize_t limit = 10; +#else + /* Set a small limit if using the pp rx pool, to avoid exhausting it. */ + ssize_t limit = 2; +#endif + + size_t usage = pp_rx_pool_usage; + ssize_t target = limit - ((ssize_t)usage - ooseq_qlen); + + if (target < 0) { + target = 0; + } + + return target; +} + +#endif /* TCP_QUEUE_OOSEQ */ + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ /* called from ieee80211_deliver_data with new IP frames */ void ethernetif_input(struct netif *netif, struct pbuf *p) { - struct eth_hdr *ethhdr = p->payload; - /* examine packet payloads ethernet header */ + struct eth_hdr *ethhdr; + if (p == NULL) { + return; + } + + if (p->payload == NULL) { + return; + } + + if (netif == NULL) { + return; + } + + ethhdr = p->payload; + + /* Account for the number of rx pool buffers being used. */ + taskENTER_CRITICAL(); + uint32_t usage = pp_rx_pool_usage + 1; + pp_rx_pool_usage = usage; + taskEXIT_CRITICAL(); switch(htons(ethhdr->type)) { /* IP or ARP packet? */ case ETHTYPE_IP: + case ETHTYPE_IPV6: +#if 0 + /* Simulate IP packet loss. */ + if ((random() & 0xff) < 0x10) { + pbuf_free(p); + return; + } +#endif + case ETHTYPE_ARP: -// case ETHTYPE_IPV6: +#if PPPOE_SUPPORT + /* PPPoE packet? */ + case ETHTYPE_PPPOEDISC: + case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ + { /* full packet send to tcpip_thread to process */ - if (netif->input(p, netif)!=ERR_OK) - { + +#if COPY_PP_RX_PBUFS + /* Optionally copy the rx pool buffer and free it immediately. This + * helps avoid exhausting the limited rx buffer pool but uses more + * memory. */ + struct pbuf *q = pbuf_clone(PBUF_RAW, PBUF_RAM, p); + pbuf_free(p); + if (q == NULL) { + return; + } + p = q; +#endif + + if (netif->input(p, netif) != ERR_OK) { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); pbuf_free(p); p = NULL; } break; + } default: pbuf_free(p); @@ -122,3 +305,98 @@ void ethernetif_input(struct netif *netif, struct pbuf *p) break; } } + +/* Since the pbuf_type definition has changed in lwip v2 and it is used by the + * sdk when calling pbuf_alloc, the SDK libraries have been modified to rename + * their references to pbuf_alloc to _pbufalloc allowing the pbuf_type to be + * rewritten here. Doing this here keeps this hack out of the lwip code, and + * ensures that this re-writing is only applied to the sdk calls to pbuf_alloc. + * + * The only pbuf types used by the SDK are type 0 for PBUF_RAM when writing + * data, and type 2 for the received data. The receive data path references + * internal buffer objects that need to be freed with custom code so a custom + * pbuf allocation type is used for these. + * + * The pbuf_layer is now also the header offset, but the sdk calls only call + * with a value of 3 which was PBUF_RAW and is now translated to a header + * offset of zero. + */ +struct pbuf *sdk_pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) { + if (type == 0) { + LWIP_ASSERT("Unexpected sdk_pbuf_alloc layer", layer == 3 || layer == 4); + return pbuf_alloc(PBUF_RAW_TX, length, PBUF_RAM); + } else if (type == 2) { + LWIP_ASSERT("Unexpected sdk_pbuf_alloc layer", layer == 3); + return pbuf_alloc_reference(NULL, length, PBUF_ALLOC_FLAG_RX | PBUF_TYPE_ALLOC_SRC_MASK_ESP_RX); + } else { + LWIP_ASSERT("Unexpected pbuf_alloc type", 0); + for (;;); + } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t +ethernetif_init(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + /* The hwaddr is currently set by sdk_wifi_station_start or + * sdk_wifi_softap_start. */ + +#if LWIP_IPV6 + // Where to do this??? + netif_create_ip6_linklocal_address(netif, 1); + netif->ip6_autoconfig_enabled = 1; + printf("ip6 link local address %s\n", ip6addr_ntoa(netif_ip6_addr(netif, 0))); +#endif + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + char *hostname = NULL; + /* Disabled for now as there were reports of crashes here, sysparam issues */ + /* sysparam_get_string("hostname", &hostname); */ + if (hostname && strlen(hostname) == 0) { + free(hostname); + hostname = NULL; + } + netif->hostname = hostname; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + // don't touch netif->state here, the field is used internally in the ESP SDK layers + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; + /* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif /* LWIP_IPV4 */ +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = low_level_output; + + /* initialize the hardware */ + low_level_init(netif); + + return ERR_OK; +} diff --git a/lwip/include/arch/cc.h b/lwip/include/arch/cc.h index 2922a54..e7cf291 100644 --- a/lwip/include/arch/cc.h +++ b/lwip/include/arch/cc.h @@ -32,36 +32,25 @@ #ifndef __ARCH_CC_H__ #define __ARCH_CC_H__ -/* include ESP SDK prototypes as they're used in some LWIP routines */ -#include "espressif/sdk_private.h" - -/* ESP8266 SDK Interface - - The lwip-esp stack is designed to be also compatible with other ESP8266 SDKs, - so we can't use our 'sdk_' prefixes there -*/ -#define system_station_got_ip_set sdk_system_station_got_ip_set -#define system_pp_recycle_rx_pkt sdk_system_pp_recycle_rx_pkt - /* Include some files for defining library routines */ #include /* printf, fflush, FILE */ #include /* abort */ #include #include #include +#include -#define ERRNO +struct ip4_addr; +struct esf_buf; +void sdk_system_station_got_ip_set(struct ip4_addr *, struct ip4_addr *, struct ip4_addr *); +void sdk_system_pp_recycle_rx_pkt(struct esf_buf *); -#define BYTE_ORDER LITTLE_ENDIAN +struct pbuf; +void pp_recycle_rx_pbuf(struct pbuf *); -/** @todo fix some warnings: don't use #pragma if compiling with cygwin gcc */ -#ifndef __GNUC__ - #include - #pragma warning (disable: 4244) /* disable conversion warning (implicit integer promotion!) */ - #pragma warning (disable: 4127) /* conditional expression is constant */ - #pragma warning (disable: 4996) /* 'strncpy' was declared deprecated */ - #pragma warning (disable: 4103) /* structure packing changed by including file */ -#endif +struct tcp_pcb; +size_t ooseq_bytes_limit(struct tcp_pcb *); +size_t ooseq_pbufs_limit(struct tcp_pcb *); /* Define generic types used in lwIP */ typedef uint8_t u8_t; @@ -112,4 +101,6 @@ typedef int sys_prot_t; #define LWIP_PLATFORM_HTONS(_n) ((u16_t)((((_n) & 0xff) << 8) | (((_n) >> 8) & 0xff))) #define LWIP_PLATFORM_HTONL(_n) ((u32_t)( (((_n) & 0xff) << 24) | (((_n) & 0xff00) << 8) | (((_n) >> 8) & 0xff00) | (((_n) >> 24) & 0xff) )) +#define LWIP_RAND() hwrand() + #endif /* __ARCH_CC_H__ */ diff --git a/lwip/include/lwipopts.h b/lwip/include/lwipopts.h index 8f46c7d..4d69eda 100644 --- a/lwip/include/lwipopts.h +++ b/lwip/include/lwipopts.h @@ -32,11 +32,15 @@ #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_OPEN_RTOS 1 + +/* See tcp.c tcp_alloc(). */ +#ifndef ESP_TIMEWAIT_THRESHOLD #define ESP_TIMEWAIT_THRESHOLD 10000 +#endif + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include in cc.h */ #define LWIP_TIMEVAL_PRIVATE 0 /* @@ -63,6 +67,34 @@ */ #define SMEMCPY(dst,src,len) memcpy(dst,src,len) +/* + ------------------------------------ + ----------- Core locking ----------- + ------------------------------------ +*/ + +/** + * LWIP_TCPIP_CORE_LOCKING + * Creates a global mutex that is held during TCPIP thread operations. + * Can be locked by client code to perform lwIP operations without changing + * into TCPIP thread using callbacks. See LOCK_TCPIP_CORE() and + * UNLOCK_TCPIP_CORE(). + * Your system should provide mutexes supporting priority inversion to use this. + */ +#define LWIP_TCPIP_CORE_LOCKING 1 + +/** + * LWIP_TCPIP_CORE_LOCKING_INPUT: when LWIP_TCPIP_CORE_LOCKING is enabled, + * this lets tcpip_input() grab the mutex for input packets as well, + * instead of allocating a message and passing it to tcpip_thread. + * + * ATTENTION: this does not work when tcpip_input() is called from + * interrupt context! + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + /* ------------------------------------ ---------- Memory options ---------- @@ -76,19 +108,36 @@ #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! -*/ + * 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 (heap alloc can be much slower than pool alloc) and usage from interrupts + * (especially if your netif driver allocates PBUF_POOL pbufs for received frames + * from interrupt)! + * ATTENTION: Currently, this uses the heap for ALL pools (also for private pools, + * not only for internal pools defined in memp_std.h)! + */ #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 + * 4 byte alignment -> \#define MEM_ALIGNMENT 4 + * 2 byte alignment -> \#define MEM_ALIGNMENT 2 */ #define MEM_ALIGNMENT 4 +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + * MEMP_OVERFLOW_CHECK == 0 no checking + * MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + * MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + * memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK 0 +#endif + /* ------------------------------------------------ ---------- Internal Memory Pool Sizes ---------- @@ -100,6 +149,14 @@ ---------- ARP options ------- -------------------------------- */ + +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP 1 +#endif + /** * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address * resolution. By default, only the most recent packet is queued per IP address. @@ -107,7 +164,9 @@ * 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. */ +#ifndef ARP_QUEUEING #define ARP_QUEUEING 1 +#endif /* -------------------------------- @@ -119,21 +178,27 @@ * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */ -#define IP_REASSEMBLY 0 +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY 1 +#endif /** * 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. */ +#ifndef IP_FRAG #define IP_FRAG 1 +#endif /** * 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. */ +#ifndef IP_REASS_MAXAGE #define IP_REASS_MAXAGE 3 +#endif /** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. @@ -141,7 +206,9 @@ * 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 +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS 2 +#endif /* ---------------------------------- @@ -163,7 +230,16 @@ /** * LWIP_DHCP==1: Enable DHCP module. */ +#ifndef LWIP_DHCP #define LWIP_DHCP 1 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK ((LWIP_DHCP) && (LWIP_ARP)) +#endif #define LWIP_DHCP_BOOTP_FILE 0 @@ -174,14 +250,21 @@ */ /* ---------------------------------- - ---------- SNMP options ---------- + ----- SNMP MIB2 support ----- ---------------------------------- */ /* ---------------------------------- - ---------- IGMP options ---------- + ----- Multicast/IGMP options ----- ---------------------------------- */ +/** + * LWIP_IGMP==1: Turn on IGMP module. + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP 1 +#endif + /* ---------------------------------- ---------- DNS options ----------- @@ -191,10 +274,19 @@ * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */ +#ifndef LWIP_DNS #define LWIP_DNS 1 +#endif +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE #define DNS_TABLE_SIZE 1 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH #define DNS_MAX_NAME_LENGTH 128 +#endif /* --------------------------------- @@ -206,30 +298,131 @@ ---------- 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. */ +#ifndef TCP_MAXRTX #define TCP_MAXRTX 6 - +#endif /** * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. */ +#ifndef TCP_SYNMAXRTX #define TCP_SYNMAXRTX 3 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ 1 +#endif + +/** + * LWIP_TCP_SACK_OUT==1: TCP will support sending selective acknowledgements (SACKs). + */ +#ifndef LWIP_TCP_SACK_OUT +#define LWIP_TCP_SACK_OUT 1 +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 536, a conservative default, + * you might want to increase this.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS 1460 +#endif + +/** + * TCP_OOSEQ_MAX_BYTES: The default maximum number of bytes queued on ooseq per + * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). + * Only valid for TCP_QUEUE_OOSEQ==1. + */ +#ifndef TCP_OOSEQ_MAX_BYTES +#define TCP_OOSEQ_MAX_BYTES (2 * TCP_MSS) +#endif + +/** + * TCP_OOSEQ_BYTES_LIMIT(ooseq): Return the maximum number of bytes to be queued + * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1. + */ +#if !defined TCP_OOSEQ_BYTES_LIMIT +#define TCP_OOSEQ_BYTES_LIMIT(ooseq) ooseq_bytes_limit(ooseq) +#endif + +/** + * TCP_OOSEQ_MAX_PBUFS: The default maximum number of pbufs queued on ooseq per + * pcb if TCP_OOSEQ_BYTES_LIMIT is not defined. Default is 0 (no limit). + * Only valid for TCP_QUEUE_OOSEQ==1. + */ +#ifndef TCP_OOSEQ_MAX_PBUFS +#define TCP_OOSEQ_MAX_PBUFS 2 +#endif + +/** + * TCP_OOSEQ_PBUFS_LIMIT(ooseq): Return the maximum number of pbufs to be queued + * on ooseq per pcb, given the pcb. Only valid for TCP_QUEUE_OOSEQ==1. + */ +#ifndef TCP_OOSEQ_PBUFS_LIMIT +#define TCP_OOSEQ_PBUFS_LIMIT(ooseq) ooseq_pbufs_limit(ooseq) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG 1 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG 2 +#endif + +/** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + * The timestamp option is currently only used to help remote hosts, it is not + * really used locally. Therefore, it is only enabled when a TS option is + * received in the initial SYN packet from a remote host. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS 1 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD LWIP_MIN((TCP_WND / 4), (TCP_MSS * 4)) +#endif /* ---------------------------------- @@ -237,19 +430,50 @@ ---------------------------------- */ +/** + * PBUF_LINK_ENCAPSULATION_HLEN: the number of bytes that should be allocated + * for an additional encapsulation header before ethernet headers (e.g. 802.11) + * + * 1. LINK_HLEN 14Byte will be remove in WLAN layer + * 2. IEEE80211_HDR_MAX_LEN needs 40 bytes. + * 3. encryption needs exra 4 bytes ahead of actual data payload, and require + * DAddr and SAddr to be 4-byte aligned. + * 4. TRANSPORT and IP are all 20, 4 bytes aligned, nice... + * 5. LCC add 6 bytes more, We don't consider WAPI yet... + * 6. define LWIP_MEM_ALIGN to be 4 Byte aligned, pbuf struct is 16B, Only thing may be + * matter is ether_hdr is not 4B aligned. + * + * So, we need extra (40 + 4 - 14) = 30 and it's happen to be 4-Byte aligned + * + * 1. lwip + * | empty 30B | eth_hdr (14B) | payload ...| + * total: 44B ahead payload + * 2. net80211 + * | max 80211 hdr, 32B | ccmp/tkip iv (8B) | sec rsv(4B) | payload ...| + * total: 40B ahead sec_rsv and 44B ahead payload + * + */ +#define PBUF_LINK_ENCAPSULATION_HLEN 36 + /* ------------------------------------------------ ---------- Network Interfaces options ---------- ------------------------------------------------ */ /** - * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME 1 +#endif + +/** + * 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 @@ -275,7 +499,9 @@ * 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 +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE 768 +#endif /** * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. @@ -327,30 +553,40 @@ * LWIP_SO_SNDTIMEO==1: Enable send timeout for sockets/netconns and * SO_SNDTIMEO processing. */ +#ifndef LWIP_SO_SNDTIMEO #define LWIP_SO_SNDTIMEO 1 +#endif /** * LWIP_SO_RCVTIMEO==1: Enable receive timeout for sockets/netconns and * SO_RCVTIMEO processing. */ +#ifndef LWIP_SO_RCVTIMEO #define LWIP_SO_RCVTIMEO 1 +#endif /** * 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) */ +#ifndef LWIP_TCP_KEEPALIVE #define LWIP_TCP_KEEPALIVE 1 +#endif /** * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. */ +#ifndef LWIP_SO_RCVBUF #define LWIP_SO_RCVBUF 0 +#endif /** * SO_REUSE==1: Enable SO_REUSEADDR option. */ +#ifndef SO_REUSE #define SO_REUSE 1 +#endif /* ---------------------------------------- @@ -358,6 +594,20 @@ ---------------------------------------- */ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS 0 +#endif + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY 0 +#endif + /* --------------------------------- ---------- PPP options ---------- @@ -375,6 +625,12 @@ ---------- IPv6 options --------------- --------------------------------------- */ +/** + * LWIP_IPV6==1: Enable IPv6 + */ +#ifndef LWIP_IPV6 +#define LWIP_IPV6 0 +#endif /* --------------------------------------- @@ -391,11 +647,29 @@ // Uncomment this line, and set the individual debug options you want, for IP stack debug output //#define LWIP_DEBUG +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +//#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_WARNING + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#define LWIP_DBG_TYPES_ON LWIP_DBG_ON + /** * ETHARP_DEBUG: Enable debugging in etharp.c. */ #define ETHARP_DEBUG LWIP_DBG_OFF +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#define NETIF_DEBUG LWIP_DBG_OFF + /** * PBUF_DEBUG: Enable debugging in pbuf.c. */ @@ -406,50 +680,151 @@ */ #define API_LIB_DEBUG LWIP_DBG_OFF +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#define API_MSG_DEBUG LWIP_DBG_OFF + /** * SOCKETS_DEBUG: Enable debugging in sockets.c. */ #define SOCKETS_DEBUG LWIP_DBG_OFF +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#define ICMP_DEBUG LWIP_DBG_OFF + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#define IGMP_DEBUG LWIP_DBG_OFF + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#define INET_DEBUG LWIP_DBG_OFF + /** * IP_DEBUG: Enable debugging for IP. */ #define IP_DEBUG LWIP_DBG_OFF +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#define IP_REASS_DEBUG LWIP_DBG_OFF + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#define RAW_DEBUG LWIP_DBG_OFF + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#define MEM_DEBUG LWIP_DBG_OFF + /** * MEMP_DEBUG: Enable debugging in memp.c. */ #define MEMP_DEBUG LWIP_DBG_OFF +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#define SYS_DEBUG LWIP_DBG_OFF + +/** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#define TIMERS_DEBUG LWIP_DBG_OFF + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#define TCP_DEBUG LWIP_DBG_OFF + /** * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. */ #define TCP_INPUT_DEBUG LWIP_DBG_OFF +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#define TCP_FR_DEBUG LWIP_DBG_OFF + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#define TCP_RTO_DEBUG LWIP_DBG_OFF + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#define TCP_CWND_DEBUG LWIP_DBG_OFF + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#define TCP_WND_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. + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. */ -#define UDP_DEBUG LWIP_DBG_OFF +#define TCP_RST_DEBUG LWIP_DBG_OFF /** - * ICMP_DEBUG: Enable debugging in udp.c. + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. */ -#define ICMP_DEBUG LWIP_DBG_OFF +#define TCP_QLEN_DEBUG LWIP_DBG_OFF + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#define UDP_DEBUG LWIP_DBG_OFF /** * TCPIP_DEBUG: Enable debugging in tcpip.c. */ #define TCPIP_DEBUG LWIP_DBG_OFF +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#define SLIP_DEBUG LWIP_DBG_OFF /** * DHCP_DEBUG: Enable debugging in dhcp.c. */ #define DHCP_DEBUG LWIP_DBG_OFF +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#define AUTOIP_DEBUG LWIP_DBG_OFF + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#define DNS_DEBUG LWIP_DBG_OFF + +/** + * IP6_DEBUG: Enable debugging for IPv6. + */ +#define IP6_DEBUG LWIP_DBG_OFF + +/* + -------------------------------------------------- + ---------- Performance tracking options ---------- + -------------------------------------------------- +*/ + #endif /* __LWIPOPTS_H__ */ diff --git a/lwip/lwip b/lwip/lwip index 3cf8d51..74676d4 160000 --- a/lwip/lwip +++ b/lwip/lwip @@ -1 +1 @@ -Subproject commit 3cf8d514bd76e6ef77e6fa514d0ec6d96da7fd9a +Subproject commit 74676d46f0bc5ed82515f8e247008b7c45ec6cf6 diff --git a/lwip/sys_arch.c b/lwip/sys_arch.c index 87d8450..1a9c5f9 100644 --- a/lwip/sys_arch.c +++ b/lwip/sys_arch.c @@ -49,17 +49,147 @@ #include "lwip/mem.h" #include "lwip/stats.h" -extern bool esp_in_isr; - -/* Based on the default xInsideISR mechanism to determine - if an ISR is running. - - Doesn't support the possibility that LWIP functions are called from the NMI - handler (none are called from NMI when using current/SDK implementation.) -*/ -static inline bool is_inside_isr() +/*---------------------------------------------------------------------------* + * Routine: sys_sem_new + *---------------------------------------------------------------------------* + * Description: + * Creates and returns a new semaphore. The "ucCount" argument specifies + * the initial state of the semaphore. + * NOTE: Currently this routine only creates counts of 1 or 0 + * Inputs: + * sys_mbox_t mbox -- Handle of mailbox + * u8_t ucCount -- Initial ucCount of semaphore (1 or 0) + * Outputs: + * sys_sem_t -- Created semaphore or 0 if could not create. + *---------------------------------------------------------------------------*/ +err_t sys_sem_new(sys_sem_t *pxSemaphore, u8_t ucCount) { - return esp_in_isr; + err_t xReturn = ERR_MEM; + + vSemaphoreCreateBinary(*pxSemaphore); + + if (*pxSemaphore != NULL) { + if (ucCount == 0U) { + xSemaphoreTake(*pxSemaphore, 1UL); + } + + xReturn = ERR_OK; + SYS_STATS_INC_USED(sem); + } else { + SYS_STATS_INC(sem.err); + } + + return xReturn; +} + +/*---------------------------------------------------------------------------* + * Routine: sys_sem_free + *---------------------------------------------------------------------------* + * Description: + * Deallocates a semaphore + * Inputs: + * sys_sem_t sem -- Semaphore to free + *---------------------------------------------------------------------------*/ +void sys_sem_free(sys_sem_t *pxSemaphore) +{ + SYS_STATS_DEC(sem.used); + vQueueDelete(*pxSemaphore); +} + +/*---------------------------------------------------------------------------* + * Routine: sys_sem_signal + *---------------------------------------------------------------------------* + * Description: + * Signals (releases) a semaphore + * Inputs: + * sys_sem_t sem -- Semaphore to signal + *---------------------------------------------------------------------------*/ +void sys_sem_signal(sys_sem_t *pxSemaphore) +{ + xSemaphoreGive(*pxSemaphore); +} + +/*---------------------------------------------------------------------------* + * Routine: sys_arch_sem_wait + *---------------------------------------------------------------------------* + * Description: + + * Blocks the thread while waiting for the semaphore to be signaled. If the + * "timeout" argument is non-zero, the thread should only be blocked for + * the specified time (measured in milliseconds). If the "timeout" argument + * is zero, the thread should be blocked until the semaphore is signalled. + * + * The return value is SYS_ARCH_TIMEOUT if the semaphore wasn't signaled + * within the specified time or any other value if it was signaled (with or + * without waiting). + * + * Notice that lwIP implements a function with a similar name, + * sys_sem_wait(), that uses the sys_arch_sem_wait() function. + * Inputs: + * sys_sem_t sem -- Semaphore to wait on + * u32_t timeout -- Number of milliseconds until timeout + * Outputs: + * u32_t -- SYS_ARCH_TIMEOUT on timeout, any other value on success + *---------------------------------------------------------------------------*/ +u32_t sys_arch_sem_wait(sys_sem_t *pxSemaphore, u32_t ulTimeout) +{ + u32_t ulReturn; + + if (ulTimeout != 0UL) { + if (xSemaphoreTake(*pxSemaphore, ulTimeout / portTICK_PERIOD_MS) == pdTRUE) { + ulReturn = 0; + } else { + ulReturn = SYS_ARCH_TIMEOUT; + } + } else { + while (xSemaphoreTake(*pxSemaphore, portMAX_DELAY) != pdTRUE); + ulReturn = 0; + } + + return ulReturn; +} + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t sys_mutex_new(sys_mutex_t *pxMutex) +{ + err_t xReturn; + + *pxMutex = xSemaphoreCreateMutex(); + + if (*pxMutex != NULL) { + xReturn = ERR_OK; + SYS_STATS_INC_USED(mutex); + } else { + xReturn = ERR_MEM; + SYS_STATS_INC(mutex.err); + } + + return xReturn; +} + +/** Lock a mutex + * @param mutex the mutex to lock */ +void sys_mutex_lock(sys_mutex_t *pxMutex) +{ + while (xSemaphoreTake(*pxMutex, portMAX_DELAY) != pdPASS); +} + +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void sys_mutex_unlock(sys_mutex_t *pxMutex) +{ + xSemaphoreGive(*pxMutex); +} + + +/** Delete a semaphore + * @param mutex the mutex to delete */ +void sys_mutex_free(sys_mutex_t *pxMutex) +{ + SYS_STATS_DEC(mutex.used); + vQueueDelete(*pxMutex); } /*---------------------------------------------------------------------------* @@ -72,16 +202,15 @@ static inline bool is_inside_isr() * Outputs: * sys_mbox_t -- Handle to new mailbox *---------------------------------------------------------------------------*/ -err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize ) +err_t sys_mbox_new(sys_mbox_t *pxMailBox, int iSize) { err_t xReturn = ERR_MEM; - *pxMailBox = xQueueCreate( iSize, sizeof( void * ) ); + *pxMailBox = xQueueCreate(iSize, sizeof(void *)); - if( *pxMailBox != NULL ) - { + if (*pxMailBox != NULL) { xReturn = ERR_OK; - SYS_STATS_INC_USED( mbox ); + SYS_STATS_INC_USED(mbox); } return xReturn; @@ -100,25 +229,24 @@ err_t sys_mbox_new( sys_mbox_t *pxMailBox, int iSize ) * Outputs: * sys_mbox_t -- Handle to new mailbox *---------------------------------------------------------------------------*/ -void sys_mbox_free( sys_mbox_t *pxMailBox ) +void sys_mbox_free(sys_mbox_t *pxMailBox) { -unsigned long ulMessagesWaiting; + unsigned long ulMessagesWaiting; - ulMessagesWaiting = uxQueueMessagesWaiting( *pxMailBox ); - configASSERT( ( ulMessagesWaiting == 0 ) ); + ulMessagesWaiting = uxQueueMessagesWaiting(*pxMailBox); + configASSERT(ulMessagesWaiting == 0); #if SYS_STATS { - if( ulMessagesWaiting != 0UL ) - { - SYS_STATS_INC( mbox.err ); + if (ulMessagesWaiting != 0UL) { + SYS_STATS_INC(mbox.err); } - SYS_STATS_DEC( mbox.used ); + SYS_STATS_DEC(mbox.used); } #endif /* SYS_STATS */ - vQueueDelete( *pxMailBox ); + vQueueDelete(*pxMailBox); } /*---------------------------------------------------------------------------* @@ -130,9 +258,9 @@ unsigned long ulMessagesWaiting; * sys_mbox_t mbox -- Handle of mailbox * void *data -- Pointer to data to post *---------------------------------------------------------------------------*/ -void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost ) +void sys_mbox_post(sys_mbox_t *pxMailBox, void *pxMessageToPost) { - while( xQueueSendToBack( *pxMailBox, &pxMessageToPost, portMAX_DELAY ) != pdTRUE ); + while (xQueueSendToBack(*pxMailBox, &pxMessageToPost, portMAX_DELAY) != pdTRUE); } /*---------------------------------------------------------------------------* @@ -148,26 +276,13 @@ void sys_mbox_post( sys_mbox_t *pxMailBox, void *pxMessageToPost ) * err_t -- ERR_OK if message posted, else ERR_MEM * if not. *---------------------------------------------------------------------------*/ -err_t sys_mbox_trypost( sys_mbox_t *pxMailBox, void *pxMessageToPost ) +err_t sys_mbox_trypost(sys_mbox_t *pxMailBox, void *pxMessageToPost) { -err_t xReturn; -portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + err_t xReturn; - if( is_inside_isr() != pdFALSE ) - { - xReturn = xQueueSendFromISR( *pxMailBox, &pxMessageToPost, &xHigherPriorityTaskWoken ); - } - else - { - xReturn = xQueueSend( *pxMailBox, &pxMessageToPost, ( TickType_t ) 0 ); - } - - if( xReturn == pdPASS ) - { + if (xQueueSend(*pxMailBox, &pxMessageToPost, 0)) { xReturn = ERR_OK; - } - else - { + } else { /* The queue was already full. */ xReturn = ERR_MEM; SYS_STATS_INC( mbox.err ); @@ -188,8 +303,8 @@ portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; * should be dropped. * * The return values are the same as for the sys_arch_sem_wait() function: - * Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a - * timeout. + * SYS_ARCH_TIMEOUT if there was a timeout, any other value if a messages + * is received. * * Note that a function with a similar name, sys_mbox_fetch(), is * implemented by lwIP. @@ -198,52 +313,28 @@ portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; * void **msg -- Pointer to pointer to msg received * u32_t timeout -- Number of milliseconds until timeout * Outputs: - * u32_t -- SYS_ARCH_TIMEOUT if timeout, else number - * of milliseconds until received. + * u32_t -- SYS_ARCH_TIMEOUT on timeout, any other value if a message has been received *---------------------------------------------------------------------------*/ -u32_t sys_arch_mbox_fetch( sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut ) +u32_t sys_arch_mbox_fetch(sys_mbox_t *pxMailBox, void **ppvBuffer, u32_t ulTimeOut) { -void *pvDummy; -TickType_t xStartTime, xEndTime, xElapsed; -unsigned long ulReturn; + void *pvDummy; + unsigned long ulReturn; - xStartTime = xTaskGetTickCount(); - - if( NULL == ppvBuffer ) - { + if (ppvBuffer == NULL) { ppvBuffer = &pvDummy; } - if( ulTimeOut != 0UL ) - { - configASSERT( is_inside_isr() == ( portBASE_TYPE ) 0 ); - - if( pdTRUE == xQueueReceive( *pxMailBox, &( *ppvBuffer ), ulTimeOut/ portTICK_PERIOD_MS ) ) - { - xEndTime = xTaskGetTickCount(); - xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS; - - ulReturn = xElapsed; - } - else - { + if (ulTimeOut != 0UL) { + if (xQueueReceive(*pxMailBox, &(*ppvBuffer), ulTimeOut / portTICK_PERIOD_MS) == pdTRUE) { + ulReturn = 0; + } else { /* Timed out. */ *ppvBuffer = NULL; ulReturn = SYS_ARCH_TIMEOUT; } - } - else - { - while( pdTRUE != xQueueReceive( *pxMailBox, &( *ppvBuffer ), portMAX_DELAY ) ); - xEndTime = xTaskGetTickCount(); - xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS; - - if( xElapsed == 0UL ) - { - xElapsed = 1UL; - } - - ulReturn = xElapsed; + } else { + while (xQueueReceive(*pxMailBox, &(*ppvBuffer), portMAX_DELAY) != pdTRUE); + ulReturn = 0; } return ulReturn; @@ -263,218 +354,24 @@ unsigned long ulReturn; * u32_t -- SYS_MBOX_EMPTY if no messages. Otherwise, * return ERR_OK. *---------------------------------------------------------------------------*/ -u32_t sys_arch_mbox_tryfetch( sys_mbox_t *pxMailBox, void **ppvBuffer ) +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *pxMailBox, void **ppvBuffer) { -void *pvDummy; -unsigned long ulReturn; -long lResult; -portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; + void *pvDummy; + unsigned long ulReturn; - if( ppvBuffer== NULL ) - { + if (ppvBuffer== NULL) { ppvBuffer = &pvDummy; } - if( is_inside_isr() != pdFALSE ) - { - lResult = xQueueReceiveFromISR( *pxMailBox, &( *ppvBuffer ), &xHigherPriorityTaskWoken ); - } - else - { - lResult = xQueueReceive( *pxMailBox, &( *ppvBuffer ), 0UL ); - } - - if( lResult == pdPASS ) - { + if (xQueueReceive(*pxMailBox, &(*ppvBuffer), 0UL) == pdPASS) { ulReturn = ERR_OK; - } - else - { + } else { ulReturn = SYS_MBOX_EMPTY; } return ulReturn; } -/*---------------------------------------------------------------------------* - * Routine: sys_sem_new - *---------------------------------------------------------------------------* - * Description: - * Creates and returns a new semaphore. The "ucCount" argument specifies - * the initial state of the semaphore. - * NOTE: Currently this routine only creates counts of 1 or 0 - * Inputs: - * sys_mbox_t mbox -- Handle of mailbox - * u8_t ucCount -- Initial ucCount of semaphore (1 or 0) - * Outputs: - * sys_sem_t -- Created semaphore or 0 if could not create. - *---------------------------------------------------------------------------*/ -err_t sys_sem_new( sys_sem_t *pxSemaphore, u8_t ucCount ) -{ -err_t xReturn = ERR_MEM; - - vSemaphoreCreateBinary( ( *pxSemaphore ) ); - - if( *pxSemaphore != NULL ) - { - if( ucCount == 0U ) - { - xSemaphoreTake( *pxSemaphore, 1UL ); - } - - xReturn = ERR_OK; - SYS_STATS_INC_USED( sem ); - } - else - { - SYS_STATS_INC( sem.err ); - } - - return xReturn; -} - -/*---------------------------------------------------------------------------* - * Routine: sys_arch_sem_wait - *---------------------------------------------------------------------------* - * Description: - * Blocks the thread while waiting for the semaphore to be - * signaled. If the "timeout" argument is non-zero, the thread should - * only be blocked for the specified time (measured in - * milliseconds). - * - * If the timeout argument is non-zero, the return value is the number of - * milliseconds spent waiting for the semaphore to be signaled. If the - * semaphore wasn't signaled within the specified time, the return value is - * SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore - * (i.e., it was already signaled), the function may return zero. - * - * Notice that lwIP implements a function with a similar name, - * sys_sem_wait(), that uses the sys_arch_sem_wait() function. - * Inputs: - * sys_sem_t sem -- Semaphore to wait on - * u32_t timeout -- Number of milliseconds until timeout - * Outputs: - * u32_t -- Time elapsed or SYS_ARCH_TIMEOUT. - *---------------------------------------------------------------------------*/ -u32_t sys_arch_sem_wait( sys_sem_t *pxSemaphore, u32_t ulTimeout ) -{ -TickType_t xStartTime, xEndTime, xElapsed; -unsigned long ulReturn; - - xStartTime = xTaskGetTickCount(); - - if( ulTimeout != 0UL ) - { - if( xSemaphoreTake( *pxSemaphore, ulTimeout / portTICK_PERIOD_MS ) == pdTRUE ) - { - xEndTime = xTaskGetTickCount(); - xElapsed = (xEndTime - xStartTime) * portTICK_PERIOD_MS; - ulReturn = xElapsed; - } - else - { - ulReturn = SYS_ARCH_TIMEOUT; - } - } - else - { - while( xSemaphoreTake( *pxSemaphore, portMAX_DELAY ) != pdTRUE ); - xEndTime = xTaskGetTickCount(); - xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS; - - if( xElapsed == 0UL ) - { - xElapsed = 1UL; - } - - ulReturn = xElapsed; - } - - return ulReturn; -} - -/** Create a new mutex - * @param mutex pointer to the mutex to create - * @return a new mutex */ -err_t sys_mutex_new( sys_mutex_t *pxMutex ) -{ -err_t xReturn = ERR_MEM; - - *pxMutex = xSemaphoreCreateMutex(); - - if( *pxMutex != NULL ) - { - xReturn = ERR_OK; - SYS_STATS_INC_USED( mutex ); - } - else - { - SYS_STATS_INC( mutex.err ); - } - - return xReturn; -} - -/** Lock a mutex - * @param mutex the mutex to lock */ -void sys_mutex_lock( sys_mutex_t *pxMutex ) -{ - while( xSemaphoreTake( *pxMutex, portMAX_DELAY ) != pdPASS ); -} - -/** Unlock a mutex - * @param mutex the mutex to unlock */ -void sys_mutex_unlock(sys_mutex_t *pxMutex ) -{ - xSemaphoreGive( *pxMutex ); -} - - -/** Delete a semaphore - * @param mutex the mutex to delete */ -void sys_mutex_free( sys_mutex_t *pxMutex ) -{ - SYS_STATS_DEC( mutex.used ); - vQueueDelete( *pxMutex ); -} - - -/*---------------------------------------------------------------------------* - * Routine: sys_sem_signal - *---------------------------------------------------------------------------* - * Description: - * Signals (releases) a semaphore - * Inputs: - * sys_sem_t sem -- Semaphore to signal - *---------------------------------------------------------------------------*/ -void sys_sem_signal( sys_sem_t *pxSemaphore ) -{ -portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; - - if( is_inside_isr() != pdFALSE ) - { - xSemaphoreGiveFromISR( *pxSemaphore, &xHigherPriorityTaskWoken ); - } - else - { - xSemaphoreGive( *pxSemaphore ); - } -} - -/*---------------------------------------------------------------------------* - * Routine: sys_sem_free - *---------------------------------------------------------------------------* - * Description: - * Deallocates a semaphore - * Inputs: - * sys_sem_t sem -- Semaphore to free - *---------------------------------------------------------------------------*/ -void sys_sem_free( sys_sem_t *pxSemaphore ) -{ - SYS_STATS_DEC(sem.used); - vQueueDelete( *pxSemaphore ); -} - /*---------------------------------------------------------------------------* * Routine: sys_init *---------------------------------------------------------------------------* @@ -508,20 +405,17 @@ u32_t sys_now(void) * Outputs: * sys_thread_t -- Pointer to per-thread timeouts. *---------------------------------------------------------------------------*/ -sys_thread_t sys_thread_new( const char *pcName, void( *pxThread )( void *pvParameters ), void *pvArg, int iStackSize, int iPriority ) +sys_thread_t sys_thread_new(const char *pcName, void(*pxThread)(void *pvParameters), void *pvArg, int iStackSize, int iPriority) { -TaskHandle_t xCreatedTask; -portBASE_TYPE xResult; -sys_thread_t xReturn; + TaskHandle_t xCreatedTask; + portBASE_TYPE xResult; + sys_thread_t xReturn; - xResult = xTaskCreate( pxThread, pcName, iStackSize, pvArg, iPriority, &xCreatedTask ); + xResult = xTaskCreate(pxThread, pcName, iStackSize, pvArg, iPriority, &xCreatedTask); - if( xResult == pdPASS ) - { + if (xResult == pdPASS) { xReturn = xCreatedTask; - } - else - { + } else { xReturn = NULL; } @@ -547,13 +441,14 @@ sys_thread_t xReturn; * Outputs: * sys_prot_t -- Previous protection level (not used here) *---------------------------------------------------------------------------*/ -sys_prot_t sys_arch_protect( void ) +static uint32_t my_nesting = 0; +sys_prot_t sys_arch_protect(void) { - if( is_inside_isr() == pdFALSE ) - { - taskENTER_CRITICAL(); - } - return ( sys_prot_t ) 1; + taskENTER_CRITICAL(); + uint32_t prev = my_nesting; + my_nesting++; + return prev; + //return (sys_prot_t)1; } /*---------------------------------------------------------------------------* @@ -567,26 +462,16 @@ sys_prot_t sys_arch_protect( void ) * Inputs: * sys_prot_t -- Previous protection level (not used here) *---------------------------------------------------------------------------*/ -void sys_arch_unprotect( sys_prot_t xValue ) +void sys_arch_unprotect(sys_prot_t xValue) { - (void) xValue; - if( is_inside_isr() == pdFALSE ) - { - taskEXIT_CRITICAL(); + //(void) xValue; + my_nesting--; + if (xValue != my_nesting) { + printf("lwip nesting %d\n", my_nesting); } + taskEXIT_CRITICAL(); } -/* - * Prints an assertion messages and aborts execution. - */ -void sys_assert( const char *pcMessage ) -{ - (void) pcMessage; - - for (;;) - { - } -} /*-------------------------------------------------------------------------* * End of File: sys_arch.c *-------------------------------------------------------------------------*/ diff --git a/open_esplibs/include/esplibs/libmain.h b/open_esplibs/include/esplibs/libmain.h index 9f4ad1a..593092c 100644 --- a/open_esplibs/include/esplibs/libmain.h +++ b/open_esplibs/include/esplibs/libmain.h @@ -56,6 +56,7 @@ uint32_t sdk_system_relative_time(uint32_t reltime); uint32_t sdk_system_get_checksum(uint8_t *, uint32_t); void sdk_wifi_softap_cacl_mac(uint8_t *, uint8_t *); void sdk_wifi_softap_set_default_ssid(void); +bool sdk_wifi_softap_set_station_info(const uint8_t *hwaddr, ip4_addr_t *); // xtensa_context.o diff --git a/open_esplibs/include/esplibs/libnet80211.h b/open_esplibs/include/esplibs/libnet80211.h index b7a2db6..d2c117b 100644 --- a/open_esplibs/include/esplibs/libnet80211.h +++ b/open_esplibs/include/esplibs/libnet80211.h @@ -32,7 +32,7 @@ struct esf_buf *sdk_ieee80211_getmgtframe(void **arg0, uint32_t arg1, uint32_t a extern uint8_t sdk_TmpSTAAPCloseAP; extern uint8_t sdk_PendFreeBcnEb; void sdk_ieee80211_hostap_attach(struct sdk_g_ic_st *); -void sdk_hostap_handle_timer(struct sdk_netif_conninfo *cnx_node); +void sdk_hostap_handle_timer(struct sdk_cnx_node *cnx_node); bool sdk_wifi_softap_start(); bool sdk_wifi_softap_stop(); @@ -85,10 +85,10 @@ int sdk_chm_check_same_channel(); extern ETSTimer sdk_sta_con_timer; extern void *sdk_g_cnx_probe_rc_list_cb; void sdk_cnx_sta_leave(struct sdk_g_ic_netif_info *netif_info, void *); -void *sdk_cnx_node_search(uint8_t mac[6]); -void sdk_cnx_node_leave(struct sdk_g_ic_netif_info *netif, struct sdk_netif_conninfo *conn); +struct sdk_cnx_node *sdk_cnx_node_search(uint8_t mac[6]); +void sdk_cnx_node_leave(struct sdk_g_ic_netif_info *netif, struct sdk_cnx_node *conn); void sdk_cnx_rc_update_state_metric(void *, int, int); -void sdk_cnx_remove_rc(void *); +void sdk_cnx_node_remove(struct sdk_cnx_node *cnx_node); void sdk_cnx_attach(struct sdk_g_ic_st *); #endif /* _ESPLIBS_LIBNET80211_H */ diff --git a/open_esplibs/include/esplibs/libpp.h b/open_esplibs/include/esplibs/libpp.h index c6185b6..836a689 100644 --- a/open_esplibs/include/esplibs/libpp.h +++ b/open_esplibs/include/esplibs/libpp.h @@ -23,6 +23,7 @@ extern uint8_t sdk_interface_mask; void sdk_ic_set_vif(int, int, uint8_t (*)[6], int, int); void sdk_ic_bss_info_update(int, uint8_t (*hwaddr)[], int, int); void sdk_ic_set_sta(int, int, void *, int, int, int, int, int); +void sdk_ic_remove_key(uint32_t); // lmac.o extern uint32_t sdk_lmacConfMib; diff --git a/open_esplibs/include/esplibs/libwpa.h b/open_esplibs/include/esplibs/libwpa.h index 36a2fc2..2839e56 100644 --- a/open_esplibs/include/esplibs/libwpa.h +++ b/open_esplibs/include/esplibs/libwpa.h @@ -53,6 +53,7 @@ int sdk_os_get_random(uint8_t *dst, uint32_t size); // wpa_auth.o uint32_t *sdk_wpa_init(uint8_t (*hwaddr)[], struct _unknown_wpa1 *, int); +void sdk_wpa_auth_sta_deinit(void *); // wpabuf.o diff --git a/open_esplibs/include/open_esplibs.h b/open_esplibs/include/open_esplibs.h index da59d3c..bcbbcd4 100644 --- a/open_esplibs/include/open_esplibs.h +++ b/open_esplibs/include/open_esplibs.h @@ -6,6 +6,10 @@ // useful for quickly troubleshooting whether a bug is due to the // reimplementation of Espressif libraries, or something else. +// Some source code is mandatory and these are not included as options here. +// For example code referencing lwip structures and flags etc that has changed +// since the initial binary code. + #ifndef OPEN_ESPLIBS #define OPEN_ESPLIBS 1 #endif @@ -32,8 +36,11 @@ #ifndef OPEN_LIBMAIN_XTENSA_CONTEXT #define OPEN_LIBMAIN_XTENSA_CONTEXT (OPEN_LIBMAIN) #endif -#ifndef OPEN_LIBMAIN_USER_INTERFACE -#define OPEN_LIBMAIN_USER_INTERFACE (OPEN_LIBMAIN) +#ifndef OPEN_LIBMAIN_ETS_TIMER +#define OPEN_LIBMAIN_ETS_TIMER (OPEN_LIBMAIN) +#endif +#ifndef OPEN_LIBMAIN_ETS_TIMER +#define OPEN_LIBMAIN_ETS_TIMER (OPEN_LIBMAIN) #endif #ifndef OPEN_LIBNET80211 @@ -42,18 +49,6 @@ #ifndef OPEN_LIBNET80211_ETS #define OPEN_LIBNET80211_ETS (OPEN_LIBNET80211) #endif -#ifndef OPEN_LIBNET80211_HOSTAP -#define OPEN_LIBNET80211_HOSTAP (OPEN_LIBNET80211) -#endif -#ifndef OPEN_LIBNET80211_INPUT -#define OPEN_LIBNET80211_INPUT (OPEN_LIBNET80211) -#endif -#ifndef OPEN_LIBNET80211_STA -#define OPEN_LIBNET80211_STA (OPEN_LIBNET80211) -#endif -#ifndef OPEN_LIBNET80211_WL_CNX -#define OPEN_LIBNET80211_WL_CNX (OPEN_LIBNET80211) -#endif #ifndef OPEN_LIBPHY #define OPEN_LIBPHY (OPEN_ESPLIBS) @@ -115,8 +110,4 @@ #define OPEN_LIBWPA_OS_XTENSA (OPEN_LIBWPA) #endif -#ifndef OPEN_LIBWPA_WPA_MAIN -#define OPEN_LIBWPA_WPA_MAIN (OPEN_LIBWPA) -#endif - #endif /* _OPEN_ESPLIBS_H */ diff --git a/open_esplibs/libmain/ets_timer.c b/open_esplibs/libmain/ets_timer.c new file mode 100644 index 0000000..44b3196 --- /dev/null +++ b/open_esplibs/libmain/ets_timer.c @@ -0,0 +1,340 @@ +/** + * Recreated Espressif libmain ets_timer.o contents. + * + * Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. + * BSD Licensed as described in the file LICENSE + * + * Copyright (c) 2016 sheinz (https://github.com/sheinz) + * + * This module seems to be adapted from NONOS SDK by Espressif to fit into + * RTOS SDK. Function sdk_ets_timer_handler_isr is no longer an ISR handler + * but still holds its name. Espressif just added a task that receives events + * from the real FRC2 timer ISR handler and calls former ISR handler. + * So, timer callbacks are called from the task context rather than an interrupt. + * + * Modifications from the original reverse engineered version: + * - FreeRTOS queue is replaced with Task notifications. + * - Removed unknown queue length monitoring and parameters allocation. + * - Removed unused debug variables + * - xTaskGenericCreate is replaced with xTaskCreate + * - simplified time to ticks conversion (simply multiply by 5) + * + * This timer should be used with caution together with other tasks. As the + * timer callback is executed within timer task context, access to data that + * other tasks accessing should be protected. + */ +#include "open_esplibs.h" + +#if OPEN_LIBMAIN_ETS_TIMER + +#if 0 + +#include "etstimer.h" +#include "espressif/osapi.h" + +void sdk_ets_timer_setfn(ETSTimer *timer, ETSTimerFunc *func, void *parg) { + sdk_os_timer_setfn(timer, func, parg); +} + +void sdk_ets_timer_arm(ETSTimer *timer, uint32_t value, bool repeat_flag) { + sdk_os_timer_arm(timer, value, repeat_flag); +} + +void sdk_ets_timer_arm_ms_us(ETSTimer *timer, uint32_t value, + bool repeat_flag, bool value_in_ms) { + sdk_os_timer_arm(timer, value * 1000 + value_in_ms, repeat_flag); +} + +void sdk_ets_timer_disarm(ETSTimer *timer) { + sdk_os_timer_disarm(timer); +} + +void sdk_ets_timer_init() { +} + +#else + +#include "open_esplibs.h" +#include +#include +#include +#include +#include +#include +#include + +typedef void ets_timer_func_t(void *); + +/** + * This structure is used for both timers: ets_timer.c and timer.c + */ +typedef struct ets_timer_st { + struct ets_timer_st *next; + TimerHandle_t timer_handle; // not used in ets_timer.c + uint32_t fire_ticks; // FRC2 timer value when timer should fire + uint32_t period_ticks; // timer value in FRC2 ticks for rpeating timers + ets_timer_func_t *callback; + bool repeat; // not used in ets_timer.c + void *timer_arg; +} ets_timer_t; + +/** + * Special values of ets_timer_t::next field + */ +#define ETS_TIMER_NOT_ARMED (ets_timer_t*)(0xffffffff) +#define ETS_TIMER_LIST_END (ets_timer_t*)(0) + +/** + * Linked list of timers + */ +static ets_timer_t* timer_list = 0; + +static TaskHandle_t task_handle = NULL; + +void sdk_ets_timer_setfn(ets_timer_t *timer, ets_timer_func_t *func, void *parg) +{ + timer->callback = func; + timer->timer_arg = parg; + timer->fire_ticks = 0; + timer->period_ticks = 0; + timer->next = ETS_TIMER_NOT_ARMED; +} + +static inline void set_alarm_value(uint32_t value) +{ + TIMER_FRC2.ALARM = value; +} + +/** + * Set timer alarm and make sure the alarm is set in the future + * and will not be missed by the timer. + */ +static void set_alarm(uint32_t ticks) +{ + uint32_t curr_time = TIMER_FRC2.COUNT; + int32_t delta = (int32_t)ticks - curr_time; + if ((delta - 40) < 1) { + if (delta < 1) { + set_alarm_value(curr_time + 40); + } else { + set_alarm_value(ticks + 44); + } + } else { + set_alarm_value(ticks); + } +} + +/** + * + * Pending timer list example: + * + * | Timer: | T0 | T1 | T2 | T3 | + * |-------------|----|----|----|----| + * | fire_ticks: | 10 | 20 | 30 | 40 | + * | next: | T1 | T2 | T3 | 0 | + * + * + * For example we need to add a timer that should fire at 25 ticks: + * + * | Timer: | T0 | T1 | new | T2 | T3 | + * |-------------|----|-----|-----|----|----| + * | fire_ticks: | 10 | 20 | 25 | 30 | 40 | + * | next: | T1 | new | T2 | T3 | 0 | + * + * We squeeze the timer into the list so the list will always remain sorted + * + * Note: if add the same timer twice the system halts +*/ +static void add_pending_timer(uint32_t ticks, ets_timer_t *timer) +{ + ets_timer_t *prev = 0; + ets_timer_t *curr = timer_list; + while (curr) { + if (((int32_t)ticks - (int32_t)curr->fire_ticks) < 1) { + // found a timer that should fire later + // so our timer should fire earlier + break; + } + prev = curr; + curr = curr->next; + } + + timer->next = curr; + timer->fire_ticks = ticks; + + if (prev != 0) { + prev->next = timer; + } else { + // Our timer is the first in the line to fire + timer_list = timer; + set_alarm(ticks); + } + + // This situation might happen if adding the same timer twice + if (timer == timer->next) { + // This seems like an error: %s is used for line number + // In the recent SDK Espressif fixed the format to "%s %u\n" + printf("%s %s \n", "ets_timer.c", (char*)209); + while (1); + } +} + +/** + * In the Espressif SDK 0.9.9 if try to arm already armed timer the system halts + * with error message. In the later SDK version Espressif changed the behavior. + * If the timer was previously armed it is disarmed and then armed without errors. + * This version recreates behavior of SDK 0.9.9 + */ +void sdk_ets_timer_arm_ms_us(ets_timer_t *timer, uint32_t value, + bool repeat_flag, bool value_in_ms) +{ + uint32_t ticks = 0; + + if (timer->next != ETS_TIMER_NOT_ARMED) { + // The error message doesn't tell what is wrong + printf("arm new %x %x\n", (uint32_t)timer, (uint32_t)timer->next); + while(1); // halt + } + + if (value_in_ms) { + ticks = value * 5000; + } else { + ticks = value * 5; + } + + if (repeat_flag) { + timer->period_ticks = ticks; + } + vPortEnterCritical(); + add_pending_timer(TIMER_FRC2.COUNT + ticks, timer); + vPortExitCritical(); +} + +void sdk_ets_timer_arm(ets_timer_t *timer, uint32_t milliseconds, + bool repeat_flag) +{ + sdk_ets_timer_arm_ms_us(timer, milliseconds, repeat_flag, + /*value in ms=*/true); +} + +void sdk_ets_timer_arm_us(ets_timer_t *timer, uint32_t useconds, + bool repeat_flag) +{ + sdk_ets_timer_arm_ms_us(timer, useconds, repeat_flag, + /*value in ms=*/false); +} + +/** + * Function removes a timer from the pending timers list. + */ +void sdk_ets_timer_disarm(ets_timer_t *timer) +{ + vPortEnterCritical(); + ets_timer_t *curr = timer_list; + ets_timer_t *prev = 0; + while (curr) { + if (curr == timer) { + if (prev) { + prev->next = curr->next; + } else { + timer_list = curr->next; + } + break; + } + prev = curr; + curr = curr->next; + } + vPortExitCritical(); + timer->next = ETS_TIMER_NOT_ARMED; + timer->period_ticks = 0; +} + +/** + * Check the list of pending timers for expired ones and process them. + */ +static inline void process_pending_timers() +{ + vPortEnterCritical(); + int32_t ticks = TIMER_FRC2.COUNT; + while (timer_list) { + if (((int32_t)timer_list->fire_ticks - ticks) < 1) { + ets_timer_t *timer = timer_list; + timer_list = timer->next; + timer->next = ETS_TIMER_NOT_ARMED; + + vPortExitCritical(); + timer->callback(timer->timer_arg); + vPortEnterCritical(); + + if (timer->next == ETS_TIMER_NOT_ARMED) { + if (timer->period_ticks) { + timer->fire_ticks = timer->fire_ticks + timer->period_ticks; + add_pending_timer(timer->fire_ticks, timer); + } + } + ticks = TIMER_FRC2.COUNT; + } else { + if (timer_list) { + set_alarm(timer_list->fire_ticks); + } + break; + } + } + vPortExitCritical(); +} + +/** + * .Lfunc002 + */ +static void IRAM frc2_isr(void *arg) +{ + BaseType_t task_woken = 0; + + BaseType_t result = xTaskNotifyFromISR(task_handle, 0, eNoAction, &task_woken); + if (result != pdTRUE) { + printf("TIMQ_FL:%d!!", (uint32_t)result); + } + + portEND_SWITCHING_ISR(task_woken); +} + +/** + * .Lfunc007 + * + * Timer task + */ +static void timer_task(void* param) +{ + while (true) { + if (xTaskNotifyWait(0, 0, NULL, portMAX_DELAY) == pdTRUE) { + process_pending_timers(); + } + } +} + +void sdk_ets_timer_init() +{ + timer_list = 0; + + _xt_isr_attach(INUM_TIMER_FRC2, frc2_isr, NULL); + + /* Original code calls xTaskGenericCreate: + * xTaskGenericCreate(task_handle, "rtc_timer_task", 200, 0, 12, &handle, + * NULL, NULL); + */ + xTaskCreate(timer_task, "rtc_timer_task", 200, 0, 12, &task_handle); + printf("frc2_timer_task_hdl:%p, prio:%d, stack:%d\n", task_handle, 12, 200); + + TIMER_FRC2.ALARM = 0; + TIMER_FRC2.CTRL = VAL2FIELD(TIMER_CTRL_CLKDIV, TIMER_CLKDIV_16) + | TIMER_CTRL_RUN; + TIMER_FRC2.LOAD = 0; + + DPORT.INT_ENABLE |= DPORT_INT_ENABLE_TIMER1; + + _xt_isr_unmask(BIT(INUM_TIMER_FRC2)); +} + +#endif + +#endif /* OPEN_LIBMAIN_ETS_TIMER */ diff --git a/open_esplibs/libmain/os_cpu_a.c b/open_esplibs/libmain/os_cpu_a.c index 7fd3719..fdabb56 100644 --- a/open_esplibs/libmain/os_cpu_a.c +++ b/open_esplibs/libmain/os_cpu_a.c @@ -69,7 +69,7 @@ void IRAM sdk__xt_int_exit(void) { "); } -void IRAM sdk__xt_timer_int(void) { +void IRAM sdk__xt_timer_int(void *arg) { uint32_t trigger_ccount; uint32_t current_ccount; uint32_t ccount_interval = portTICK_PERIOD_MS * sdk_os_get_cpu_frequency() * 1000; diff --git a/open_esplibs/libmain/user_interface.c b/open_esplibs/libmain/user_interface.c index eed34a1..a21530d 100644 --- a/open_esplibs/libmain/user_interface.c +++ b/open_esplibs/libmain/user_interface.c @@ -3,9 +3,6 @@ Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. BSD Licensed as described in the file LICENSE */ -#include "open_esplibs.h" -#if OPEN_LIBMAIN_USER_INTERFACE -// The contents of this file are only built if OPEN_LIBMAIN_USER_INTERFACE is set to true #include "FreeRTOS.h" #include "task.h" @@ -147,8 +144,8 @@ bool IRAM sdk_system_rtc_mem_read(uint32_t src_addr, void *des_addr, uint16_t sa return true; } -void sdk_system_pp_recycle_rx_pkt(void *eb) { - sdk_ppRecycleRxPkt(eb); +void sdk_system_pp_recycle_rx_pkt(struct esf_buf *esf_buf) { + sdk_ppRecycleRxPkt(esf_buf); } uint16_t sdk_system_adc_read(void) { @@ -471,8 +468,7 @@ uint32_t sdk_system_relative_time(uint32_t reltime) { return WDEV.SYS_TIME - reltime; } -// Change arg types to ip4_addr for lwip v2. -void sdk_system_station_got_ip_set(struct ip_addr *ip, struct ip_addr *mask, struct ip_addr *gw) { +void sdk_system_station_got_ip_set(struct ip4_addr *ip, struct ip4_addr *mask, struct ip4_addr *gw) { uint8_t *ip_bytes = (uint8_t *)&ip->addr; uint8_t *mask_bytes = (uint8_t *)&mask->addr; uint8_t *gw_bytes = (uint8_t *)&gw->addr; @@ -588,9 +584,9 @@ bool sdk_wifi_get_ip_info(uint8_t if_index, struct ip_info *info) { if (!info) return false; struct netif *netif = _get_netif(if_index); if (netif) { - info->ip = netif->ip_addr; - info->netmask = netif->netmask; - info->gw = netif->gw; + ip4_addr_set(&info->ip, ip_2_ip4(&netif->ip_addr)); + ip4_addr_set(&info->netmask, ip_2_ip4(&netif->netmask)); + ip4_addr_set(&info->gw, ip_2_ip4(&netif->gw)); return true; } @@ -719,5 +715,3 @@ bool sdk_wifi_set_sleep_type(enum sdk_sleep_type type) sdk_pm_set_sleep_type_from_upper(type); return true; } - -#endif /* OPEN_LIBMAIN_USER_INTERFACE */ diff --git a/open_esplibs/libnet80211/ieee80211_hostap.c b/open_esplibs/libnet80211/ieee80211_hostap.c index fbe7f49..74f9675 100644 --- a/open_esplibs/libnet80211/ieee80211_hostap.c +++ b/open_esplibs/libnet80211/ieee80211_hostap.c @@ -3,8 +3,306 @@ Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. BSD Licensed as described in the file LICENSE */ -#include "open_esplibs.h" -#if OPEN_LIBNET80211_HOSTAP -// The contents of this file are only built if OPEN_LIBNET80211_HOSTAP is set to true -#endif /* OPEN_LIBNET80211_HOSTAP */ +#include +#include "tcpip.h" +#include "espressif/esp_wifi.h" +#include "espressif/esp_misc.h" +#include "etstimer.h" +#include "esplibs/libmain.h" +#include "esplibs/libnet80211.h" +#include "esplibs/libpp.h" +#include "esplibs/libwpa.h" + +static uint8_t hostap_flags = 0; +static ETSTimer hostap_timer; +static struct esf_buf *hostap_timer_parg = NULL; + +void IRAM *zalloc(size_t nbytes); + +static void IRAM hostap_timer_func(struct esf_buf *esf_buf) { + struct sdk_cnx_node *cnx_node = sdk_g_ic.v.softap_netif_info->cnx_nodes[0]; + int32_t mode = sdk_wifi_get_phy_mode(); + uint8_t *frame = esf_buf->frame; + *(uint16_t *)(frame + 22) = (cnx_node->_unknown9c - 1) << 4; + + cnx_node->_unknown9c += 1; + + if (sdk_g_ic.s.wifi_led_enable) { + uint32_t gpio = sdk_g_ic.s.wifi_led_gpio; + uint32_t state = sdk_g_ic.s.wifi_led_state; + sdk_gpio_output_set(state << gpio, (((state & 1) == 0) ? 1 : 0) << gpio, + 1 << gpio, 0); + sdk_g_ic.s.wifi_led_state = (state & 1) ? 0 : 1; + } + + uint8_t *frame2 = frame + sdk_g_ic.s._unknown288 + (mode == 1 ? 23 : 27) ; + memcpy(frame2 + 29, &sdk_g_ic.v._unknown1d2, 1); + + uint32_t v1 = frame2[26]; + if (v1 == 0) { + v1 = frame2[27]; + } + frame2[26] = v1 - 1; + + uint32_t v2 = sdk_ieee80211_chan2ieee(sdk_g_ic.v._unknown14c); + frame2[23] = v2; + sdk_g_ic.s._unknown30d = v2; + + int32_t v3 = *((volatile int32_t *)0x3ff20c00); // mactime + *(uint32_t *)(esf_buf->extra + 16) = v3; + *(uint32_t *)(frame + 24) = v3; + *(uint32_t *)(frame + 28) = 0; + + if (sdk_chm_check_same_channel()) { + hostap_flags |= 1; + sdk_ppTxPkt(esf_buf); + return; + } + sdk_ets_timer_disarm(&hostap_timer); + sdk_ets_timer_arm(&hostap_timer, sdk_wDev_Get_Next_TBTT(), 0); +} + +static void IRAM hostap_tx_callback() { + uint32_t flags = hostap_flags & 0xfe; + + if (sdk_TmpSTAAPCloseAP == 0) { + hostap_flags = flags; + sdk_ets_timer_disarm(&hostap_timer); + sdk_ets_timer_arm(&hostap_timer, sdk_wDev_Get_Next_TBTT(), 0); + return; + } + + sdk_PendFreeBcnEb = 1; + + if (flags & 2) { + hostap_flags = flags & 0xfd; + sdk_wifi_softap_start(); + return; + } + + hostap_flags = flags; +} + +static void hostap_attach_misc() { + struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.softap_netif_info; + + struct _unknown_softap1 *ptr1 = zalloc(28); // 0x1c + netif_info->_unknownb4 = ptr1; + + struct _unknown_softap2 *ptr2 = zalloc(204); // 0xcc + ptr1->_unknown04 = ptr2; + + struct _unknown_wpa1 *ptr3 = zalloc(76); // 0x4c + + uint32_t v1 = sdk_g_ic.s._unknown30e; + if (v1 == 2) { + ptr3->_unknown00 = 1; + } else if (v1 == 3) { + ptr3->_unknown00 = 2; + } else if (v1 == 4) { + ptr3->_unknown00 = 3; + } + + ptr3->_unknown28 = 2; + ptr3->_unknown04 = 2; + ptr3->_unknown0c = 2; + ptr3->_unknown08 = 10; + ptr3->_unknown20 = 10; + + int s1 = (sdk_g_ic.s._unknown28a << 16) | sdk_g_ic.s._unknown288; + memcpy(&ptr2->_unknown10, &sdk_g_ic.s._unknown28c, s1); + ptr2->_unknown30 = s1; + + uint8_t *ptr4 = zalloc(64); // 0x40 + ptr2->_unknown3c = ptr4; + + char *str1 = sdk_g_ic.s._unknown2ac; + memcpy(ptr4, str1, strlen(str1)); + + struct sdk_cnx_node *cnx_node = netif_info->cnx_nodes[0]; + + ptr2->_unknownb4 = 300; + + netif_info->_unknown4c = 3; + netif_info->_unknown48 |= 16; + + cnx_node->_unknown08 |= 1; + + sdk_hostapd_setup_wpa_psk(ptr2); + + struct netif *netif = netif_info->netif; + + ptr1->_unknown18 = sdk_wpa_init(&netif->hwaddr, ptr3, 0); + + free(ptr3); +} + +static void softap_stop_free() { + struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.softap_netif_info; + netif_info->_unknown4c = 0; + netif_info->_unknown48 &= 0xffffffef; + netif_info->cnx_nodes[0]->_unknown08 = 0; + + struct _unknown_softap1 *unkb4 = netif_info->_unknownb4; + if (!unkb4) return; + + uint32_t *unk18 = unkb4->_unknown18; + if (unk18) { + uint32_t *ptr1 = ((uint32_t **)unk18)[20]; + if (ptr1) + free(ptr1); + + uint32_t *ptr2 = *(uint32_t **)unk18; + if (ptr2) + free(ptr2); + + free(unk18); + } + + struct _unknown_softap2 *unk04 = unkb4->_unknown04; + if (unk04) { + uint32_t *unk38 = unk04->_unknown38; + if (unk38) + free(unk38); + + uint8_t *unk3c = unk04->_unknown3c; + if (unk3c) + free(unk3c); + + free(unk04); + } + + free(unkb4); + netif_info->_unknownb4 = NULL; +} + +void sdk_ieee80211_hostap_attach(struct sdk_g_ic_st *ic) { + uint32_t scratch[12]; // ?? + struct sdk_g_ic_netif_info *netif_info = ic->v.softap_netif_info; + + uint32_t v1 = ic->s._unknown30e; + if (v1 >= 2 && v1 < 5) + hostap_attach_misc(); + + struct netif *netif = netif_info->netif; + sdk_ic_bss_info_update(1, &netif->hwaddr, 2, 100); + + ic->v._unknown1d0 = 0; + netif_info->_unknown3c = 5; + + sdk_ppRegisterTxCallback(hostap_tx_callback, 4); + + hostap_timer_parg = sdk_ieee80211_beacon_alloc(netif_info, scratch); + sdk_ets_timer_disarm(&hostap_timer); + sdk_ets_timer_setfn(&hostap_timer, (ETSTimerFunc *)hostap_timer_func, hostap_timer_parg); + sdk_wDev_Reset_TBTT(); + sdk_ets_timer_arm(&hostap_timer, sdk_wDev_Get_Next_TBTT(), 0); +} + +bool sdk_wifi_softap_start() { + struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.softap_netif_info; + if (!netif_info) return 0; + if (netif_info->started) return 1; + + uint8_t flags = hostap_flags; + if (flags & 1) { + hostap_flags = flags | 2; + return 1; + } + + uint8_t (*mac_addr)[6] = &sdk_info.softap_mac_addr; + if (!netif_info->netif) { + struct netif *netif = (struct netif *)malloc(sizeof(struct netif)); + netif_info->netif = netif; + memcpy(&netif->hwaddr, mac_addr, 6); + netif_add(netif, &sdk_info.softap_ipaddr, &sdk_info.softap_netmask, + &sdk_info.softap_gw, netif_info, ethernetif_init, tcpip_input); + } + + sdk_ic_set_vif(1, 1, mac_addr, 1, 0); + + netif_set_up(netif_info->netif); + + if (sdk_wifi_get_opmode() != 3 || + !sdk_g_ic.v.station_netif_info || + sdk_g_ic.v.station_netif_info->_unknown3c < 2) { + + uint32_t i1 = (sdk_g_ic.s._unknown30d - 1) & 0xff; + + int nmi_on = sdk_NMIIrqIsOn; + if (!nmi_on) { + vPortEnterCritical(); + + do { + DPORT.DPORT0 = DPORT.DPORT0 & 0xffffffe0; + } while (DPORT.DPORT0 & 1); + } + + // current channel? + uint32_t *chan = &sdk_g_ic.v._unknown84[i1 * 3]; + sdk_g_ic.v._unknown14c = chan; + + if (!nmi_on) { + DPORT.DPORT0 = (DPORT.DPORT0 & 0xffffffe0) | 1; + vPortExitCritical(); + } + + sdk_chm_set_current_channel(chan); + } + + sdk_ieee80211_hostap_attach(&sdk_g_ic); + sdk_TmpSTAAPCloseAP = 0; + netif_info->started = 1; + return 1; +} + +bool sdk_wifi_softap_stop() { + struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.softap_netif_info; + + if (!netif_info) + return 0; + + if (!netif_info->started) + return 1; + + uint32_t end = sdk_g_ic.s._unknown310 + 2; + uint32_t count = 1; + + // Note this defensive test seems dead code, the value is loaded + // as a uint8_t value so adding 2 ensures this test always passes. + if (end >= 2) { + do { + struct sdk_cnx_node *cnx_node = netif_info->cnx_nodes[count]; + if (cnx_node) { + struct sdk_cnx_node *cnx_node2 = netif_info->_unknown88; + netif_info->_unknown88 = cnx_node; + + sdk_ieee80211_send_mgmt(netif_info, 160, 4); + sdk_ieee80211_send_mgmt(netif_info, 192, 2); + + netif_info->_unknown88 = cnx_node2; + + sdk_cnx_node_leave(netif_info, netif_info->cnx_nodes[count]); + + // Number of entries might have changed, perhaps + // should have if one was removed above? + end = sdk_g_ic.s._unknown310 + 2; + } + count++; + } while (count < end); + } + + netif_set_down(netif_info->netif); + sdk_TmpSTAAPCloseAP = 1; + sdk_ets_timer_disarm(&hostap_timer); + sdk_ic_bss_info_update(1, &sdk_info.softap_mac_addr, 2, 0); + sdk_ic_set_vif(1, 0, NULL, 1, 0); + softap_stop_free(); + + if ((hostap_flags & 1) == 0) + sdk_esf_buf_recycle(hostap_timer_parg, 4); + + netif_info->started = 0; + return 1; +} diff --git a/open_esplibs/libnet80211/ieee80211_input.c b/open_esplibs/libnet80211/ieee80211_input.c index be07a51..583dba9 100644 --- a/open_esplibs/libnet80211/ieee80211_input.c +++ b/open_esplibs/libnet80211/ieee80211_input.c @@ -3,9 +3,6 @@ Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. BSD Licensed as described in the file LICENSE */ -#include "open_esplibs.h" -#if OPEN_LIBNET80211_INPUT -// The contents of this file are only built if OPEN_LIBNET80211_INPUT is set to true #include "esplibs/libpp.h" @@ -14,10 +11,9 @@ void IRAM sdk_ieee80211_deliver_data(struct sdk_g_ic_netif_info *netif_info, str if (netif->flags & NETIF_FLAG_LINK_UP) { uint16_t length = esf_buf->length; - struct pbuf *pbuf = pbuf_alloc(PBUF_RAW, length, PBUF_REF); - pbuf->payload = esf_buf->pbuf2->payload; + struct pbuf *pbuf = pbuf_alloc_reference(esf_buf->pbuf2->payload, length, PBUF_ALLOC_FLAG_RX | PBUF_TYPE_ALLOC_SRC_MASK_ESP_RX); esf_buf->pbuf1 = pbuf; - pbuf->eb = (void *)esf_buf; + pbuf->esf_buf = (void *)esf_buf; ethernetif_input(netif, pbuf); return; } @@ -27,5 +23,3 @@ void IRAM sdk_ieee80211_deliver_data(struct sdk_g_ic_netif_info *netif_info, str return; } - -#endif /* OPEN_LIBNET80211_INPUT */ diff --git a/open_esplibs/libnet80211/ieee80211_sta.c b/open_esplibs/libnet80211/ieee80211_sta.c index 5362dc3..3e7f695 100644 --- a/open_esplibs/libnet80211/ieee80211_sta.c +++ b/open_esplibs/libnet80211/ieee80211_sta.c @@ -3,9 +3,6 @@ Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. BSD Licensed as described in the file LICENSE */ -#include "open_esplibs.h" -#if OPEN_LIBNET80211_STA -// The contents of this file are only built if OPEN_LIBNET80211_STA is set to true #include #include "esplibs/libmain.h" @@ -72,5 +69,3 @@ bool sdk_wifi_station_stop() { return 1; } - -#endif /* OPEN_LIBNET80211_STA */ diff --git a/open_esplibs/libnet80211/wl_cnx.c b/open_esplibs/libnet80211/wl_cnx.c index 3b7d709..3b49c5d 100644 --- a/open_esplibs/libnet80211/wl_cnx.c +++ b/open_esplibs/libnet80211/wl_cnx.c @@ -3,17 +3,103 @@ Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. BSD Licensed as described in the file LICENSE */ -#include "open_esplibs.h" -#if OPEN_LIBNET80211_WL_CNX -// The contents of this file are only built if OPEN_LIBNET80211_WL_CNX is set to true #include "espressif/esp_misc.h" #include "esplibs/libnet80211.h" +#include "esplibs/libpp.h" +#include "esplibs/libwpa.h" #include #include "lwip/dhcp.h" -ETSTimer sdk_sta_con_timer; -void *sdk_g_cnx_probe_rc_list_cb; +/* Need to use the sdk versions of these for now as there are reference to them + * relative to other data structres. */ +extern ETSTimer sdk_sta_con_timer; +extern void *sdk_g_cnx_probe_rc_list_cb; + +/* + * Called from the ESP sdk_cnx_sta_leave function. Split out via a hack to the + * binary library to allow modification to track changes to lwip, for example + * changes to the offset of the netif->flags removal of the NETIF_FLAG_DHCP flag + * lwip v2 etc. + */ +void dhcp_if_down(struct netif *netif) +{ + dhcp_release_and_stop(netif); + netif_set_down(netif); +} + +struct sdk_cnx_node *sdk_cnx_rc_search(uint8_t *hwaddr) { + size_t len = *(uint8_t *)(sdk_g_ic.v._unknown0 + 0x689); + struct sdk_cnx_node **table = (struct sdk_cnx_node **)(sdk_g_ic.v._unknown0 + 0x670); + size_t i; + + for (i = 0; i < len; i++) { + struct sdk_cnx_node *cnx_node = table[i]; + if (cnx_node && memcmp(cnx_node->mac_addr, hwaddr, 6) == 0) { + return cnx_node; + } + } + + return NULL; +} + +int sdk_cnx_add_rc(struct sdk_cnx_node *cnx_node) { + size_t len = *(uint8_t *)(sdk_g_ic.v._unknown0 + 0x689); + struct sdk_cnx_node **table = (struct sdk_cnx_node **)(sdk_g_ic.v._unknown0 + 0x670); + + if (len >= 6) { + return -1; + } + + if (len < 2) { + table[len] = cnx_node; + } else { + struct wl_channel *channel = cnx_node->channel; + size_t found; + for (found = 0; found < len; found++) { + if (table[found]->channel == channel) { + break; + } + } + + if (found >= len) { + /* Add to the end. */ + table[len] = cnx_node; + } else { + /* Make room. */ + size_t next = found + 1; + size_t i; + for (i = len; i > next; i--) { + table[i] = table[i - 1];; + } + table[next] = cnx_node; + } + } + + *(uint8_t *)(sdk_g_ic.v._unknown0 + 0x689) += 1; + return 0; +} + +void sdk_cnx_remove_rc(struct sdk_cnx_node *cnx_node) { + size_t len = *(uint8_t *)(sdk_g_ic.v._unknown0 + 0x689); + struct sdk_cnx_node **table = (struct sdk_cnx_node **)(sdk_g_ic.v._unknown0 + 0x670); + size_t i; + + for (i = 0; i < len; i++) { + if (table[i] == cnx_node) { + bzero(cnx_node, 0x110); + table[i] = NULL; + len -= 1; + *(uint8_t *)(sdk_g_ic.v._unknown0 + 0x689) = len; + break; + } + } + + /* Fill the hole */ + for (; i < len; i++) { + table[i] = table[i + 1]; + } +} #if 0 @@ -24,7 +110,6 @@ static uint8_t Ldata004; static uint32_t Ldata006; static void *Ldate007; -// Use of the netif->flags and the NETIF_FLAG_DHCP flag removed in lwip v2. void sdk_cnx_sta_leave(struct sdk_g_ic_netif_info *netif_info, void *arg1) { struct netif *netif = netif_info->netif; @@ -32,13 +117,9 @@ void sdk_cnx_sta_leave(struct sdk_g_ic_netif_info *netif_info, void *arg1) { uint16_t v1 = *(uint16_t *)(arg1 + 0x1a) & 0xfff; sdk_ic_set_sta(0, 0, arg1, 0, v1, phy_type, 0, 0); - netif_set_down(netif); - - // The NETIF_FLAG_DHCP flags is removed in lwip v2? - if (netif->flags & 0x8) { - dhcp_release(netif); - dhcp_stop(netif); - } + // Note the SDK binary was modified here as it made use of the + // netif flags which changed in lwip v2. + dhcp_if_down(netif); uint32_t v2 = *(uint8_t *)(arg1 + 0xe8); free(sdk_g_ic.v._unknown190[v2]); @@ -77,7 +158,30 @@ void sdk_cnx_sta_leave(struct sdk_g_ic_netif_info *netif_info, void *arg1) { } #endif -void IRAM *sdk_cnx_node_search(uint8_t mac[6]) +void sdk_cnx_node_remove(struct sdk_cnx_node *cnx_node) { + const uint32_t num = sdk_g_ic.s._unknown310 + 2; + if ((int32_t)num < (int32_t)2) { + return; + } + + struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.softap_netif_info; + uint32_t i = 1; + do { + if (netif_info->cnx_nodes[i] == cnx_node) { + uint32_t v2 = cnx_node->_unknowne8; + sdk_ic_remove_key(v2 + 2); + sdk_wpa_auth_sta_deinit(cnx_node->_unknowne4); + free(sdk_g_ic.v._unknown190[v2]); + sdk_g_ic.v._unknown190[v2] = NULL; + free(cnx_node); + netif_info->cnx_nodes[i] = NULL; + return; + } + i += 1; + } while (i < num); +} + +struct sdk_cnx_node *sdk_cnx_node_search(uint8_t mac[6]) { int end = sdk_g_ic.s._unknown310 + 2; @@ -86,15 +190,15 @@ void IRAM *sdk_cnx_node_search(uint8_t mac[6]) if (end < 1) return NULL; - struct sdk_netif_conninfo **conninfo = sdk_g_ic.v.softap_netif_info->conninfo; + struct sdk_cnx_node **cnx_nodes = sdk_g_ic.v.softap_netif_info->cnx_nodes; int i = 0; do { - struct sdk_netif_conninfo *info = conninfo[i]; + struct sdk_cnx_node *cnx_node = cnx_nodes[i]; - if (info) { - if (memcmp(mac, info->mac_addr, 6) == 0) { - return info; + if (cnx_node) { + if (memcmp(mac, cnx_node->mac_addr, 6) == 0) { + return cnx_node; } } i++; @@ -102,5 +206,3 @@ void IRAM *sdk_cnx_node_search(uint8_t mac[6]) return NULL; } - -#endif /* OPEN_LIBNET80211_WL_CNX */ diff --git a/open_esplibs/libpp/wdev.c b/open_esplibs/libpp/wdev.c index 1564a59..902b3dc 100644 --- a/open_esplibs/libpp/wdev.c +++ b/open_esplibs/libpp/wdev.c @@ -5,7 +5,13 @@ */ #include "open_esplibs.h" #if OPEN_LIBPP_WDEV -// The contents of this file are only built if OPEN_LIBPHY_PHY_CHIP_SLEEP is set to true +// The contents of this file are only built if OPEN_LIBPP_WDEV is set to true +// Note the SDK allocated 8000 bytes for TX buffers that appears to be +// unused. Rather TX buffers appear to be allocated by upper layers. The +// location of this areas is at wDevCtrl + 0x2190. The SDK has been modified +// to allocate only one word (4 bytes) per buffer on initialization and even +// these seem unused but to be sure avoid the first 20 bytes. So there are +// 7980 bytes free starting at wDevCtrl + 0x21a4. #endif /* OPEN_LIBPP_WDEV */ diff --git a/open_esplibs/libwpa/wpa_main.c b/open_esplibs/libwpa/wpa_main.c index 1c70516..e13e3b6 100644 --- a/open_esplibs/libwpa/wpa_main.c +++ b/open_esplibs/libwpa/wpa_main.c @@ -3,13 +3,13 @@ Copyright (C) 2015 Espressif Systems. Derived from MIT Licensed SDK libraries. BSD Licensed as described in the file LICENSE */ -#include "open_esplibs.h" -#if OPEN_LIBWPA_WPA_MAIN -// The contents of this file are only built if OPEN_LIBWPA_WPA_MAIN is set to true +#include +#include #include "espressif/user_interface.h" #include "etstimer.h" #include "espressif/osapi.h" +#include "espressif/esp_sta.h" #include "esplibs/libnet80211.h" #include "esplibs/libmain.h" #include "esplibs/libwpa.h" @@ -44,8 +44,8 @@ void sdk_wpa_config_bss(struct sdk_g_ic_st *g_ic, uint8_t (* hwaddr2)[6]) { struct sdk_g_ic_netif_info *netif_info = g_ic->v.station_netif_info; struct netif *netif = netif_info->netif; sdk_wpa_set_bss(netif->hwaddr, hwaddr2, g_ic->s._unknown20a, g_ic->s._unknown20c, - g_ic->s.sta_password, g_ic->s._unknown1e4.sta_ssid, - (g_ic->s._unknown1e4._unknown1e6 << 16) | g_ic->s._unknown1e4._unknown1e4); + g_ic->s.sta_password, g_ic->s.sta_ssid.ssid, + g_ic->s.sta_ssid.ssid_length); } void sdk_wpa_config_assoc_ie(int arg0, int16_t *arg1, int32_t arg2) { @@ -57,14 +57,14 @@ void sdk_wpa_config_assoc_ie(int arg0, int16_t *arg1, int32_t arg2) { *arg1 = arg2; } -void sdk_dhcp_bind_check() { +void sdk_dhcp_bind_check(void *parg) { struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.station_netif_info; uint8_t connect_status = netif_info->connect_status; uint8_t unknown20a = sdk_g_ic.s._unknown20a; - if (connect_status != 5) { + if (connect_status != STATION_GOT_IP) { if (unknown20a == 7 || unknown20a == 8) { - netif_info->connect_status = 2; + netif_info->connect_status = STATION_CONNECTING; } } } @@ -72,13 +72,13 @@ void sdk_dhcp_bind_check() { void sdk_eagle_auth_done() { struct sdk_g_ic_netif_info *netif_info = sdk_g_ic.v.station_netif_info; struct netif *netif = netif_info->netif; - struct sdk_netif_conninfo *conninfo = netif_info->_unknown88; + struct sdk_cnx_node *cnx_node = netif_info->_unknown88; - if (conninfo->_unknown08 & 1) + if (cnx_node->_unknown08 & 1) return; - uint32_t channel = conninfo->_unknown78->channel; - char *ssid = (char *)sdk_g_ic.s._unknown1e4.sta_ssid; + uint32_t channel = cnx_node->channel->num; + char *ssid = (char *)sdk_g_ic.s.sta_ssid.ssid; printf("\nconnected with %s, channel %d\n", ssid, channel); RTCMEM_SYSTEM[61] = 0x00010000 | channel; @@ -89,24 +89,29 @@ void sdk_eagle_auth_done() { sdk_os_timer_arm(timer, 15000, 0); netif_info->statusb9 = 0; - conninfo->_unknown18 = 0; - conninfo->_unknown08 |= 1; + cnx_node->_unknown18 = 0; + cnx_node->_unknown08 |= 1; - // TODO lwip v2 removed the NETIF_FLAG_DHCP flag. - if (netif->flags & 0x08) // NETIF_FLAG_DHCP + if (dhcp_supplied_address(netif)) return; - // lwip v2: if (ip4_addr_isany_val(netif->ip_addr)) { - if (netif->ip_addr.addr == 0) { - if (sdk_dhcpc_flag != DHCP_STOPPED) { - printf("dhcp client start...\n"); - dhcp_start(netif); - } + if (sdk_dhcpc_flag != DHCP_STOPPED) { + printf("dhcp client start...\n"); + netif_set_up(netif); + dhcp_start(netif); return; } - system_station_got_ip_set(&netif->ip_addr, &netif->netmask, &netif->gw); + if (ip4_addr_isany_val(sdk_info.sta_ipaddr)) { + printf("expected a static ip address?\n"); + return; + } + + netif_set_addr(netif, &sdk_info.sta_ipaddr, &sdk_info.sta_netmask, &sdk_info.sta_gw); netif_set_up(netif); + sdk_system_station_got_ip_set(ip_2_ip4(&netif->ip_addr), + ip_2_ip4(&netif->netmask), + ip_2_ip4(&netif->gw)); } void sdk_wpa_neg_complete() { @@ -120,5 +125,3 @@ void sdk_wpa_attach(struct sdk_g_ic_st *g_ic) { wpa_callback2, sdk_wpa_neg_complete); sdk_ppRegisterTxCallback(sdk_eapol_txcb, 3); } - -#endif /* OPEN_LIBWPA_WPA_MAIN */ diff --git a/parameters.mk b/parameters.mk index 8c6a8a3..4dede4e 100644 --- a/parameters.mk +++ b/parameters.mk @@ -66,7 +66,7 @@ COMPONENTS ?= $(EXTRA_COMPONENTS) FreeRTOS lwip core open_esplibs SDK_LIBS ?= main net80211 phy pp wpa # open source libraries linked in -LIBS ?= hal gcc c +LIBS ?= hal # set to 0 if you want to use the toolchain libc instead of esp-open-rtos newlib OWN_LIBC ?= 1 @@ -90,7 +90,7 @@ C_CXX_FLAGS ?= -Wall -Wl,-EL -nostdlib $(EXTRA_C_CXX_FLAGS) # Flags for C only CFLAGS ?= $(C_CXX_FLAGS) -std=gnu99 $(EXTRA_CFLAGS) # Flags for C++ only -CXXFLAGS ?= $(C_CXX_FLAGS) -fno-exceptions -fno-rtti $(EXTRA_CXXFLAGS) +CXXFLAGS ?= $(C_CXX_FLAGS) -std=c++0x -fno-exceptions -fno-rtti $(EXTRA_CXXFLAGS) # these aren't all technically preprocesor args, but used by all 3 of C, C++, assembler CPPFLAGS += -mlongcalls -mtext-section-literals diff --git a/tests/cases/03_byte_load_flash.c b/tests/cases/03_byte_load_flash.c index b8dcb8e..ccbe50e 100644 --- a/tests/cases/03_byte_load_flash.c +++ b/tests/cases/03_byte_load_flash.c @@ -290,7 +290,7 @@ static void a_03_byte_load_test_isr() printf("Testing behaviour inside ISRs...\r\n"); timer_set_interrupts(FRC1, false); timer_set_run(FRC1, false); - _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler); + _xt_isr_attach(INUM_TIMER_FRC1, frc1_interrupt_handler, NULL); timer_set_frequency(FRC1, 1000); timer_set_interrupts(FRC1, true); timer_set_run(FRC1, true); diff --git a/tests/cases/07_sysparam.c b/tests/cases/07_sysparam.c new file mode 100644 index 0000000..c1a4697 --- /dev/null +++ b/tests/cases/07_sysparam.c @@ -0,0 +1,403 @@ + +#include +#include + +#include +#include + +#include + +#include + +// #define DEBUG + +#ifdef DEBUG +#include +#define debug(fmt, ...) printf("%s" fmt, "test: ", ## __VA_ARGS__); +#else +#define debug(fmt, ...) +#endif + +DEFINE_SOLO_TESTCASE(07_sysparam_basic_test); +DEFINE_SOLO_TESTCASE(07_sysparam_load_test); +DEFINE_SOLO_TESTCASE(07_sysparam_bool_test); + +#define TEST_ITERATIONS 10 +#define KEY_BUF_SIZE 32 +#define TEST_STRING_BUF_SIZE 64 +#define NUMBER_OF_TEST_DATA 20 + +typedef struct { + uint32_t start_key_index; + uint32_t key_index; +} test_data_t; + +typedef enum { + VALUE_STRING = 0, + VALUE_INT32, + VALUE_INT8, + VALUE_BOOL, + VALUE_ENUM_END +} value_type_t; + + +static uint32_t get_current_time() +{ + return timer_get_count(FRC2) / 5000; // to get roughly 1ms resolution +} + +/** + * Recreate sysparam area + */ +static inline void init_sysparam() +{ + sysparam_status_t status; + uint32_t base_addr, num_sectors; + + status = sysparam_get_info(&base_addr, &num_sectors); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + status = sysparam_create_area(base_addr, num_sectors, /*force=*/true); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + status = sysparam_init(base_addr, 0); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + debug("sysparam initialized at addr=%x, sectors=%d\n", + base_addr, num_sectors); +} + +/** + * Initialize test data with random seed. + */ +static void test_data_init(test_data_t *data) +{ + debug("test_data_init\n"); + data->start_key_index = data->key_index = rand() % 100; +} + +/** + * Reset test data to the initial seed. + */ +static void test_data_reset(test_data_t *data) +{ + debug("test_data_reset\n"); + data->key_index = data->start_key_index; +} + +/** + * Get key string for the current data. + */ +static void test_data_get_key(test_data_t *data, char *key_buf) +{ + sprintf(key_buf, "key_%d", data->key_index); + debug("test_data_get_key: key=%s\n", key_buf); +} + +/** + * Generate test string for the current data. + */ +static void test_data_get_string(test_data_t *data, char *str_buf) +{ + srand(data->key_index); + for (int i = 0; i < TEST_STRING_BUF_SIZE - 1; ++i) { + str_buf[i] = '0' + rand() % 74; // generate a char 0-9,a-z,A-Z and other + } + str_buf[TEST_STRING_BUF_SIZE-1] = 0; // terminate string with zero + debug("test_data_get_string: str=%s\n", str_buf); +} + +/** + * Generate test int32 value for the current data. + */ +static int32_t test_data_get_int32(test_data_t *data) +{ + srand(data->key_index); + int32_t v = rand(); + debug("test_data_get_int32: value=%d\n", v); + return v; +} + +/** + * Generate test int8 value for the current data. + */ +int8_t test_data_get_int8(test_data_t *data) +{ + srand(data->key_index); + int8_t v = rand() % 256; + debug("test_data_get_int8: value=%d\n", v); + return v; +} + +/** + * Generate test bool value for the current data. + */ +bool test_data_get_bool(test_data_t *data) +{ + srand(data->key_index); + bool v = rand() % 2; + debug("test_data_get_bool, value=%s\n", v ? "true" : "false"); + return v; +} + +/** + * Get type of the current data. + */ +value_type_t test_data_get_type(test_data_t *data) +{ + srand(data->key_index); + value_type_t t = rand() % VALUE_ENUM_END; + debug("test_data_get_type: type=%d\n", t); + return t; +} + +/** + * Generate next data. + */ +void test_data_next(test_data_t *data) +{ + data->key_index++; + debug("test_data_next: key_index=%d\n", data->key_index); +} + +static void write_test_values(test_data_t *data) +{ + sysparam_status_t status = SYSPARAM_ERR_BADVALUE; + char key_buf[KEY_BUF_SIZE]; + char str_buf[TEST_STRING_BUF_SIZE]; + + for (int i = 0; i < NUMBER_OF_TEST_DATA; ++i) { + test_data_get_key(data, key_buf); + switch (test_data_get_type(data)) { + case VALUE_STRING: + test_data_get_string(data, str_buf); + status = sysparam_set_string(key_buf, str_buf); + break; + case VALUE_INT32: + status = sysparam_set_int32(key_buf, test_data_get_int32(data)); + break; + case VALUE_INT8: + status = sysparam_set_int8(key_buf, test_data_get_int8(data)); + break; + case VALUE_BOOL: + status = sysparam_set_bool(key_buf, test_data_get_bool(data)); + break; + case VALUE_ENUM_END: + default: + break; + } + + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + test_data_next(data); + } +} + +static void verify_test_values(test_data_t *data) +{ + sysparam_status_t status = SYSPARAM_ERR_BADVALUE; + char key_buf[KEY_BUF_SIZE]; + char expected_str_buf[TEST_STRING_BUF_SIZE]; + char *actual_str; + int32_t actual_int32; + int8_t actual_int8; + bool actual_bool; + + for (int i = 0; i < NUMBER_OF_TEST_DATA; ++i) { + test_data_get_key(data, key_buf); + switch (test_data_get_type(data)) { + case VALUE_STRING: + test_data_get_string(data, expected_str_buf); + status = sysparam_get_string(key_buf, &actual_str); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_EQUAL_STRING(expected_str_buf, actual_str); + free(actual_str); + break; + case VALUE_INT32: + status = sysparam_get_int32(key_buf, &actual_int32); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_EQUAL_INT(test_data_get_int32(data), actual_int32); + break; + case VALUE_INT8: + status = sysparam_get_int8(key_buf, &actual_int8); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_EQUAL_INT(test_data_get_int8(data), actual_int8); + break; + case VALUE_BOOL: + status = sysparam_get_bool(key_buf, &actual_bool); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_TRUE(test_data_get_bool(data) == actual_bool); + break; + case VALUE_ENUM_END: + default: + break; + } + + test_data_next(data); + } +} + +static void clear_test_values(test_data_t *data) +{ + char key_buf[KEY_BUF_SIZE]; + sysparam_status_t status = SYSPARAM_ERR_BADVALUE; + + for (int i = 0; i < NUMBER_OF_TEST_DATA; ++i) { + test_data_get_key(data, key_buf); + status = sysparam_set_data(key_buf, NULL, 0, false); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + test_data_next(data); + } +} + + +static void a_07_sysparam_load_test(void) +{ + test_data_t test_data; + init_sysparam(); + uint32_t start_time = get_current_time(); + uint32_t free_heap_at_start = xPortGetFreeHeapSize(); + + for (int i = 0; i < TEST_ITERATIONS; ++i) { + test_data_init(&test_data); + write_test_values(&test_data); + test_data_reset(&test_data); + verify_test_values(&test_data); + test_data_reset(&test_data); + clear_test_values(&test_data); + } + + TEST_ASSERT_EQUAL_INT_MESSAGE(free_heap_at_start, xPortGetFreeHeapSize(), + "Free heap size is less than at test start. Possible memory leak."); + + printf("Test took %d ms\n", get_current_time() - start_time); + + TEST_PASS(); +} + +static void a_07_sysparam_basic_test(void) +{ + sysparam_status_t status; + int32_t int32_val = 0; + int8_t int8_val = 0; + char *str; + bool bool_val; + + init_sysparam(); + + status = sysparam_set_int32("int_1", -123); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + status = sysparam_get_int32("int_1", &int32_val); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_EQUAL_INT(-123, int32_val); + + status = sysparam_set_int8("int_2", -34); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + status = sysparam_get_int8("int_2", &int8_val); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_EQUAL_INT(-34, int8_val); + + status = sysparam_set_string("str_1", "test string"); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + status = sysparam_get_string("str_1", &str); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_EQUAL_STRING("test string", str); + free(str); + + status = sysparam_set_bool("bool_true", true); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + status = sysparam_get_bool("bool_true", &bool_val); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_TRUE(bool_val); + + status = sysparam_set_bool("bool_false", false); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + status = sysparam_get_bool("bool_false", &bool_val); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_FALSE(bool_val); + + TEST_PASS(); +} + +typedef struct { + const char *key; + const char *str; + bool value; +} bool_test_data_t; + +const static bool_test_data_t bool_data[] = { + {"str_true", "true", true}, + {"str_True", "True", true}, + {"str_TRUE", "TRUE", true}, + {"str_t", "t", true}, + {"str_T", "T", true}, + {"str_y", "y", true}, + {"str_Y", "Y", true}, + {"str_yes", "yes", true}, + {"str_Yes", "Yes", true}, + {"str_YES", "YES", true}, + {"str_1", "1", true}, + + {"str_false", "false", false}, + {"str_False", "False", false}, + {"str_FALSE", "FALSE", false}, + {"str_f", "f", false}, + {"str_F", "F", false}, + {"str_n", "n", false}, + {"str_N", "N", false}, + {"str_no", "no", false}, + {"str_No", "No", false}, + {"str_NO", "NO", false}, + {"str_0", "0", false}, +}; + +static void a_07_sysparam_bool_test(void) +{ + sysparam_status_t status; + bool value; + + init_sysparam(); + + for (int i = 0; i < sizeof(bool_data) / sizeof(bool_data[0]); ++i) { + status = sysparam_set_string(bool_data[i].key, bool_data[i].str); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + } + + status = sysparam_set_int8("int8_0", 0); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + status = sysparam_set_int8("int8_1", 1); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + status = sysparam_set_int32("int32_0", 0); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + status = sysparam_set_int32("int32_1", 1); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + + for (int i = 0; i < sizeof(bool_data) / sizeof(bool_data[0]); ++i) { + debug("Getting bool key=%s\n", bool_data[i].key); + status = sysparam_get_bool(bool_data[i].key, &value); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_TRUE(bool_data[i].value == value); + } + + status = sysparam_get_bool("int8_0", &value); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_FALSE(value); + + status = sysparam_get_bool("int8_1", &value); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_TRUE(value); + + status = sysparam_get_bool("int32_0", &value); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_FALSE(value); + + status = sysparam_get_bool("int32_1", &value); + TEST_ASSERT_EQUAL_INT(SYSPARAM_OK, status); + TEST_ASSERT_TRUE(value); + + TEST_PASS(); +} diff --git a/tests/cases/08_spiflash.c b/tests/cases/08_spiflash.c new file mode 100644 index 0000000..67b2783 --- /dev/null +++ b/tests/cases/08_spiflash.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DEFINE_SOLO_TESTCASE(08_spiflash_unaligned) + +/** + * Test unaligned access to spi flash. + */ +static void a_08_spiflash_unaligned(void) +{ + const int test_addr = 0x100000 - (4096 * 8); + const char test_str[] = "test_string"; + const int buf_size = 256; + uint8_t buf[buf_size]; + + TEST_ASSERT_TRUE(spiflash_erase_sector(test_addr)); + TEST_ASSERT_TRUE(spiflash_erase_sector(test_addr + 4096)); + + TEST_ASSERT_TRUE( + spiflash_write(test_addr, (uint8_t*)test_str, sizeof(test_str))); + + TEST_ASSERT_TRUE(spiflash_read(test_addr, buf, buf_size)); + + TEST_ASSERT_EQUAL_STRING(test_str, buf); + + TEST_ASSERT_TRUE( + spiflash_write(test_addr + 31, (uint8_t*)test_str, sizeof(test_str))); + TEST_ASSERT_TRUE(spiflash_read(test_addr + 31, buf, buf_size)); + TEST_ASSERT_EQUAL_STRING(test_str, buf); + + TEST_ASSERT_TRUE( + spiflash_write(test_addr + 101, (uint8_t*)test_str, sizeof(test_str))); + TEST_ASSERT_TRUE(spiflash_read(test_addr + 101, buf + 1, buf_size - 1)); + TEST_ASSERT_EQUAL_STRING(test_str, buf + 1); + + TEST_ASSERT_TRUE( + spiflash_write(test_addr + 201, (uint8_t*)test_str + 1, sizeof(test_str) - 1)); + TEST_ASSERT_TRUE(spiflash_read(test_addr + 201, buf + 1, buf_size - 1)); + TEST_ASSERT_EQUAL_STRING(test_str + 1, buf + 1); + + TEST_PASS(); +}