1.将A27新UI文件夹重命名为CANUI 2.A272O新版本发布

This commit is contained in:
2025-03-26 18:43:18 +08:00
parent 497f8eb1e1
commit 5bc7ee438c
13399 changed files with 58500 additions and 59183 deletions

View File

@ -0,0 +1,258 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_crc.c
* @ingroup CRC
*
* @defgroup CRC CRC Checksums for Strings
* @brief Provides fast hashing functions.
*
**/
#include "ff_headers.h"
/*static*/ const uint32_t crc32_table[ 256 ] =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
};
uint32_t FF_GetCRC32( uint8_t * pbyData,
uint32_t stLength )
{
register uint32_t crc = 0xFFFFFFFF;
while( stLength-- != 0 )
{
crc = ( ( crc >> 8 ) & 0x00FFFFFF ) ^ crc32_table[ ( crc ^ *( pbyData++ ) ) & 0x000000FF ];
}
return crc ^ 0xFFFFFFFF;
}
static const uint8_t crc16_table_low[ 256 ] =
{
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x000, 0x0c1, 0x081, 0x040, 0x001, 0x0c0, 0x080, 0x041,
0x001, 0x0c0, 0x080, 0x041, 0x000, 0x0c1, 0x081, 0x040,
};
static const uint8_t crc16_table_high[ 256 ] =
{
0x000, 0x0c0, 0x0c1, 0x001, 0x0c3, 0x003, 0x002, 0x0c2,
0x0c6, 0x006, 0x007, 0x0c7, 0x005, 0x0c5, 0x0c4, 0x004,
0x0cc, 0x00c, 0x00d, 0x0cd, 0x00f, 0x0cf, 0x0ce, 0x00e,
0x00a, 0x0ca, 0x0cb, 0x00b, 0x0c9, 0x009, 0x008, 0x0c8,
0x0d8, 0x018, 0x019, 0x0d9, 0x01b, 0x0db, 0x0da, 0x01a,
0x01e, 0x0de, 0x0df, 0x01f, 0x0dd, 0x01d, 0x01c, 0x0dc,
0x014, 0x0d4, 0x0d5, 0x015, 0x0d7, 0x017, 0x016, 0x0d6,
0x0d2, 0x012, 0x013, 0x0d3, 0x011, 0x0d1, 0x0d0, 0x010,
0x0f0, 0x030, 0x031, 0x0f1, 0x033, 0x0f3, 0x0f2, 0x032,
0x036, 0x0f6, 0x0f7, 0x037, 0x0f5, 0x035, 0x034, 0x0f4,
0x03c, 0x0fc, 0x0fd, 0x03d, 0x0ff, 0x03f, 0x03e, 0x0fe,
0x0fa, 0x03a, 0x03b, 0x0fb, 0x039, 0x0f9, 0x0f8, 0x038,
0x028, 0x0e8, 0x0e9, 0x029, 0x0eb, 0x02b, 0x02a, 0x0ea,
0x0ee, 0x02e, 0x02f, 0x0ef, 0x02d, 0x0ed, 0x0ec, 0x02c,
0x0e4, 0x024, 0x025, 0x0e5, 0x027, 0x0e7, 0x0e6, 0x026,
0x022, 0x0e2, 0x0e3, 0x023, 0x0e1, 0x021, 0x020, 0x0e0,
0x0a0, 0x060, 0x061, 0x0a1, 0x063, 0x0a3, 0x0a2, 0x062,
0x066, 0x0a6, 0x0a7, 0x067, 0x0a5, 0x065, 0x064, 0x0a4,
0x06c, 0x0ac, 0x0ad, 0x06d, 0x0af, 0x06f, 0x06e, 0x0ae,
0x0aa, 0x06a, 0x06b, 0x0ab, 0x069, 0x0a9, 0x0a8, 0x068,
0x078, 0x0b8, 0x0b9, 0x079, 0x0bb, 0x07b, 0x07a, 0x0ba,
0x0be, 0x07e, 0x07f, 0x0bf, 0x07d, 0x0bd, 0x0bc, 0x07c,
0x0b4, 0x074, 0x075, 0x0b5, 0x077, 0x0b7, 0x0b6, 0x076,
0x072, 0x0b2, 0x0b3, 0x073, 0x0b1, 0x071, 0x070, 0x0b0,
0x050, 0x090, 0x091, 0x051, 0x093, 0x053, 0x052, 0x092,
0x096, 0x056, 0x057, 0x097, 0x055, 0x095, 0x094, 0x054,
0x09c, 0x05c, 0x05d, 0x09d, 0x05f, 0x09f, 0x09e, 0x05e,
0x05a, 0x09a, 0x09b, 0x05b, 0x099, 0x059, 0x058, 0x098,
0x088, 0x048, 0x049, 0x089, 0x04b, 0x08b, 0x08a, 0x04a,
0x04e, 0x08e, 0x08f, 0x04f, 0x08d, 0x04d, 0x04c, 0x08c,
0x044, 0x084, 0x085, 0x045, 0x087, 0x047, 0x046, 0x086,
0x082, 0x042, 0x043, 0x083, 0x041, 0x081, 0x080, 0x040,
};
/*****************************************************************************
* Description: Function to 16 bit CRC check a block of memory
*
*
* Parameters: pbyData - Pointer to the source data
* stLength - The length to CRC
*
* Return value: The 16 bit CRC value
*
*****************************************************************************/
uint16_t FF_GetCRC16( uint8_t * pbyData,
uint32_t stLength )
{
uint8_t bTableValue;
uint16_t wCRC = 0;
while( stLength-- != 0 )
{
bTableValue = ( uint8_t ) ( ( wCRC & 0x00FF ) ^ *pbyData++ );
wCRC = ( uint16_t ) ( ( ( crc16_table_high[ bTableValue ] ) << 8 ) +
( crc16_table_low[ bTableValue ] ^ ( ( wCRC >> 8 ) & 0x00FF ) ) );
}
return wCRC;
}
static const uint8_t crc8_table[ 256 ] =
{
0, 94, 188, 226, 97, 63, 221, 131,
194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30,
95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160,
225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61,
124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197,
132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88,
25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230,
167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123,
58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15,
78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146,
211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44,
109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177,
240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73,
8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212,
149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106,
43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247,
182, 232, 10, 84, 215, 137, 107, 53
};
/*****************************************************************************
* Description: Function to CRC check a block of memory
*
* Parameters: pbyData - Pointer to the source data
* stLength - The length to CRC
*
* Return value: The 8 bit CRC value
*
*****************************************************************************/
uint8_t FF_GetCRC8( uint8_t * pbyData,
uint32_t stLength )
{
uint8_t byCRC = 0, byData;
while( stLength-- != 0 )
{
byData = *pbyData++;
byCRC = crc8_table[ ( byCRC ^ byData ) ];
}
return byCRC;
}

View File

@ -0,0 +1,252 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "portable.h"
#include "ff_headers.h"
#include "ff_devices.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE( x ) ( int ) ( sizeof( x ) / sizeof( x )[ 0 ] )
#endif
#if ( ffconfigDEV_SUPPORT == 0 )
#error No use to include this module if ffconfigDEV_SUPPORT is disabled
#endif /* ffconfigDEV_SUPPORT == 0 */
struct SFileCache
{
char pcFileName[ 16 ];
uint32_t ulFileLength;
uint32_t ulFilePointer;
};
struct SFileCache xFiles[ 16 ];
enum eCACHE_ACTION
{
eCACHE_LOOKUP,
eCACHE_ADD,
eCACHE_REMOVE,
};
const char pcDevicePath[] = ffconfigDEV_PATH;
struct SFileCache * pxFindFile( const char * pcFname,
enum eCACHE_ACTION eAction )
{
BaseType_t xIndex, xFreeIndex = -1;
struct SFileCache * pxResult = NULL;
for( xIndex = 0; xIndex < ARRAY_SIZE( xFiles ); xIndex++ )
{
if( xFiles[ xIndex ].pcFileName[ 0 ] == '\0' )
{
if( xFreeIndex < 0 )
{
xFreeIndex = xIndex;
}
}
else if( strcmp( xFiles[ xIndex ].pcFileName, pcFname ) == 0 )
{
if( eAction == eCACHE_REMOVE )
{
xFiles[ xIndex ].pcFileName[ 0 ] = '\0';
}
pxResult = xFiles + xIndex;
break;
}
}
if( ( pxResult == NULL ) && ( eAction == eCACHE_ADD ) && ( xFreeIndex >= 0 ) )
{
pxResult = xFiles + xFreeIndex;
snprintf( pxResult->pcFileName, sizeof( pxResult->pcFileName ), "%s", pcFname );
pxResult->ulFileLength = 0;
pxResult->ulFilePointer = 0;
}
return pxResult;
}
BaseType_t xCheckDevicePath( const char * pcPath )
{
BaseType_t xDevLength;
BaseType_t xPathLength;
BaseType_t xIsDevice;
xDevLength = sizeof( pcDevicePath ) - 1;
xPathLength = strlen( pcPath );
/* System "/dev" should not match with "/device/etc". */
if( ( xPathLength >= xDevLength ) &&
( memcmp( pcDevicePath, pcPath, xDevLength ) == 0 ) &&
( ( pcPath[ xDevLength ] == '\0' ) || ( pcPath[ xDevLength ] == '/' ) ) )
{
xIsDevice = FF_DEV_CHAR_DEV;
}
else
{
xIsDevice = FF_DEV_NO_DEV;
}
return xIsDevice;
}
BaseType_t FF_Device_Open( const char * pcPath,
FF_FILE * pxStream )
{
uint8_t ucIsDevice;
ucIsDevice = xCheckDevicePath( pcPath );
if( ucIsDevice != pdFALSE )
{
const char * pcBaseName = pcPath;
if( memcmp( pcBaseName, pcDevicePath, sizeof( pcDevicePath ) - 1 ) == 0 )
{
pcBaseName = pcBaseName + sizeof( pcDevicePath );
}
pxStream->pxDevNode = pxFindFile( pcBaseName, eCACHE_ADD );
if( pxStream->pxDevNode != NULL )
{
pxStream->pxDevNode->ulFilePointer = 0;
if( ( pxStream->ucMode & ( FF_MODE_WRITE | FF_MODE_APPEND | FF_MODE_CREATE ) ) == 0 )
{
pxStream->ulFileSize = pxStream->pxDevNode->ulFileLength;
}
}
}
return ucIsDevice;
}
void FF_Device_Close( FF_FILE * pxStream )
{
if( pxStream->pxDevNode != NULL )
{
pxStream->ulFileSize = 0ul;
pxStream->ulFilePointer = 0ul;
}
}
size_t FF_Device_Read( void * pvBuf,
size_t lSize,
size_t lCount,
FF_FILE * pxStream )
{
lCount *= lSize;
return lCount;
}
size_t FF_Device_Write( const void * pvBuf,
size_t lSize,
size_t lCount,
FF_FILE * pxStream )
{
lCount *= lSize;
if( pxStream->pxDevNode != NULL )
{
pxStream->pxDevNode->ulFilePointer += lCount;
if( pxStream->pxDevNode->ulFileLength < pxStream->pxDevNode->ulFilePointer )
{
pxStream->pxDevNode->ulFileLength = pxStream->pxDevNode->ulFilePointer;
}
}
return lCount;
}
int FF_Device_Seek( FF_FILE * pxStream,
long lOffset,
int iWhence )
{
if( pxStream->pxDevNode != NULL )
{
if( iWhence == FF_SEEK_SET )
{
pxStream->pxDevNode->ulFilePointer = lOffset;
}
else if( iWhence == FF_SEEK_END )
{
pxStream->pxDevNode->ulFilePointer = pxStream->pxDevNode->ulFileLength - lOffset;
}
}
return 0;
}
int FF_Device_GetDirEnt( const char * pcPath,
FF_DirEnt_t * pxDirEnt )
{
BaseType_t xIsDotDir = 0;
if( pxDirEnt->pcFileName[ 0 ] == '.' )
{
if( ( pxDirEnt->pcFileName[ 1 ] == '.' ) &&
( pxDirEnt->pcFileName[ 2 ] == '\0' ) )
{
xIsDotDir = 2;
}
else if( pxDirEnt->pcFileName[ 1 ] == '\0' )
{
xIsDotDir = 1;
}
}
if( xIsDotDir == 0 )
{
struct SFileCache * pxDevNode;
pxDevNode = pxFindFile( pxDirEnt->pcFileName, eCACHE_LOOKUP );
pxDirEnt->ucIsDeviceDir = FF_DEV_CHAR_DEV;
if( pxDevNode != NULL )
{
pxDirEnt->ulFileSize = pxDevNode->ulFileLength;
}
else if( pxDirEnt->ulFileSize < 2048 )
{
pxDirEnt->ulFileSize = 2048;
}
}
return 1024;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,318 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_error.c
* @ingroup ERROR
*
* @defgroup ERR Error Message
* @brief Used to return human readable strings for FreeRTOS+FAT error codes.
*
**/
#include <stdio.h>
#include "ff_headers.h"
#if !defined( ARRAY_SIZE )
#define ARRAY_SIZE( x ) ( int ) ( sizeof( x ) / sizeof( x )[ 0 ] )
#endif
/* This if-block spans the rest of the source file.*/
#if ( ffconfigDEBUG != 0 )
const struct _FFMODULETAB
{
const char * const strModuleName;
const uint8_t ucModuleID;
}
xFreeRTOSFATModuleTable[] =
{
{ "Unknown Module", 1 }, /* 1 here is ok, as the GetError functions start at the end of the table. */
{ "ff_ioman.c", FF_GETMODULE( FF_MODULE_IOMAN ) },
{ "ff_dir.c", FF_GETMODULE( FF_MODULE_DIR ) },
{ "ff_file.c", FF_GETMODULE( FF_MODULE_FILE ) },
{ "ff_fat.c", FF_GETMODULE( FF_MODULE_FAT ) },
{ "ff_crc.c", FF_GETMODULE( FF_MODULE_CRC ) },
{ "ff_format.c", FF_GETMODULE( FF_MODULE_FORMAT ) },
{ "ff_memory.c", FF_GETMODULE( FF_MODULE_MEMORY ) },
{ "ff_string.c", FF_GETMODULE( FF_MODULE_STRING ) },
{ "ff_locking.c", FF_GETMODULE( FF_MODULE_LOCKING ) },
{ "ff_time.c", FF_GETMODULE( FF_MODULE_TIME ) },
{ "Platform Driver", FF_GETMODULE( FF_MODULE_DRIVER ) },
};
#if ( ffconfigHAS_FUNCTION_TAB != 0 )
const struct _FFFUNCTIONTAB
{
const char * const strFunctionName;
const uint16_t ucFunctionID;
}
xFreeRTOSFATFunctionTable[] =
{
{ "Unknown Function", 1 },
/*----- FF_IOManager_t - The FreeRTOS+FAT I/O Manager */
{ "FF_CreateIOManger", FF_GETMOD_FUNC( FF_CREATEIOMAN ) },
{ "FF_DeleteIOManager", FF_GETMOD_FUNC( FF_DESTROYIOMAN ) },
{ "FF_Mount", FF_GETMOD_FUNC( FF_MOUNT ) },
{ "FF_Unmount", FF_GETMOD_FUNC( FF_UNMOUNT ) },
{ "FF_FlushCache", FF_GETMOD_FUNC( FF_FLUSHCACHE ) },
{ "FF_GetPartitionBlockSize", FF_GETMOD_FUNC( FF_GETPARTITIONBLOCKSIZE ) },
{ "FF_BlockRead", FF_GETMOD_FUNC( FF_BLOCKREAD ) },
{ "FF_BlockWrite", FF_GETMOD_FUNC( FF_BLOCKWRITE ) },
{ "FF_DetermineFatType", FF_GETMOD_FUNC( FF_DETERMINEFATTYPE ) },
{ "FF_GetEfiPartitionEntry", FF_GETMOD_FUNC( FF_GETEFIPARTITIONENTRY ) },
{ "FF_UserDriver", FF_GETMOD_FUNC( FF_USERDRIVER ) },
{ "FF_DecreaseFreeClusters", FF_GETMOD_FUNC( FF_DECREASEFREECLUSTERS ) },
{ "FF_IncreaseFreeClusters", FF_GETMOD_FUNC( FF_INCREASEFREECLUSTERS ) },
{ "FF_PartitionSearch", FF_GETMOD_FUNC( FF_PARTITIONSEARCH ) },
{ "FF_ParseExtended", FF_GETMOD_FUNC( FF_PARSEEXTENDED ) },
/*----- FF_DIR - The FreeRTOS+FAT directory handling routines */
{ "FF_FetchEntryWithContext", FF_GETMOD_FUNC( FF_FETCHENTRYWITHCONTEXT ) },
{ "FF_PushEntryWithContext", FF_GETMOD_FUNC( FF_PUSHENTRYWITHCONTEXT ) },
{ "FF_GetEntry", FF_GETMOD_FUNC( FF_GETENTRY ) },
{ "FF_FindFirst", FF_GETMOD_FUNC( FF_FINDFIRST ) },
{ "FF_FindNext", FF_GETMOD_FUNC( FF_FINDNEXT ) },
{ "FF_RewindFind", FF_GETMOD_FUNC( FF_REWINDFIND ) },
{ "FF_FindFreeDirent", FF_GETMOD_FUNC( FF_FINDFREEDIRENT ) },
{ "FF_PutEntry", FF_GETMOD_FUNC( FF_PUTENTRY ) },
{ "FF_CreateShortName", FF_GETMOD_FUNC( FF_CREATESHORTNAME ) },
{ "FF_CreateLFNs", FF_GETMOD_FUNC( FF_CREATELFNS ) },
{ "FF_ExtendDirectory", FF_GETMOD_FUNC( FF_EXTENDDIRECTORY ) },
{ "FF_MkDir", FF_GETMOD_FUNC( FF_MKDIR ) },
{ "FF_Traverse", FF_GETMOD_FUNC( FF_TRAVERSE ) },
{ "FF_FindDir", FF_GETMOD_FUNC( FF_FINDDIR ) },
/*----- FF_FILE - The FreeRTOS+FAT file handling routines */
{ "FF_GetModeBits", FF_GETMOD_FUNC( FF_GETMODEBITS ) },
{ "FF_Open", FF_GETMOD_FUNC( FF_OPEN ) },
{ "FF_isDirEmpty", FF_GETMOD_FUNC( FF_ISDIREMPTY ) },
{ "FF_RmDir", FF_GETMOD_FUNC( FF_RMDIR ) },
{ "FF_RmFile", FF_GETMOD_FUNC( FF_RMFILE ) },
{ "FF_Move", FF_GETMOD_FUNC( FF_MOVE ) },
{ "FF_isEOF", FF_GETMOD_FUNC( FF_ISEOF ) },
{ "FF_GetSequentialClusters", FF_GETMOD_FUNC( FF_GETSEQUENTIALCLUSTERS ) },
{ "FF_ReadClusters", FF_GETMOD_FUNC( FF_READCLUSTERS ) },
{ "FF_ExtendFile", FF_GETMOD_FUNC( FF_EXTENDFILE ) },
{ "FF_WriteClusters", FF_GETMOD_FUNC( FF_WRITECLUSTERS ) },
{ "FF_Read", FF_GETMOD_FUNC( FF_READ ) },
{ "FF_GetC", FF_GETMOD_FUNC( FF_GETC ) },
{ "FF_GetLine", FF_GETMOD_FUNC( FF_GETLINE ) },
{ "FF_Tell", FF_GETMOD_FUNC( FF_TELL ) },
{ "FF_Write", FF_GETMOD_FUNC( FF_WRITE ) },
{ "FF_PutC", FF_GETMOD_FUNC( FF_PUTC ) },
{ "FF_Seek", FF_GETMOD_FUNC( FF_SEEK ) },
{ "FF_Invalidate", FF_GETMOD_FUNC( FF_INVALIDATE ) },
{ "FF_CheckValid", FF_GETMOD_FUNC( FF_CHECKVALID ) },
{ "FF_Close", FF_GETMOD_FUNC( FF_CLOSE ) },
{ "FF_SetTime", FF_GETMOD_FUNC( FF_SETTIME ) },
{ "FF_BytesLeft", FF_GETMOD_FUNC( FF_BYTESLEFT ) },
{ "FF_SetFileTime", FF_GETMOD_FUNC( FF_SETFILETIME ) },
{ "FF_InitBuf", FF_GETMOD_FUNC( FF_INITBUF ) },
/*----- FF_FAT - The FreeRTOS+FAT FAT handling routines */
{ "FF_getFATEntry", FF_GETMOD_FUNC( FF_GETFATENTRY ) },
{ "FF_ClearCluster", FF_GETMOD_FUNC( FF_CLEARCLUSTER ) },
{ "FF_putFATEntry", FF_GETMOD_FUNC( FF_PUTFATENTRY ) },
{ "FF_FindFreeCluster", FF_GETMOD_FUNC( FF_FINDFREECLUSTER ) },
{ "FF_CountFreeClusters", FF_GETMOD_FUNC( FF_COUNTFREECLUSTERS ) },
/*----- FF_UNICODE - The FreeRTOS+FAT hashing routines */
{ "FF_Utf8ctoUtf16c", FF_GETMOD_FUNC( FF_UTF8CTOUTF16C ) },
{ "FF_Utf16ctoUtf8c", FF_GETMOD_FUNC( FF_UTF16CTOUTF8C ) },
{ "FF_Utf32ctoUtf16c", FF_GETMOD_FUNC( FF_UTF32CTOUTF16C ) },
{ "FF_Utf16ctoUtf32c", FF_GETMOD_FUNC( FF_UTF16CTOUTF32C ) },
/*----- FF_FORMAT - The FreeRTOS+FAT format routine */
{ "FF_FormatPartition", FF_GETMOD_FUNC( FF_FORMATPARTITION ) },
/*----- FF_STDIO - The FreeRTOS+FAT stdio front-end */
{ "ff_chmod", FF_GETMOD_FUNC( FF_CHMOD ) },
{ "ff_stat", FF_GETMOD_FUNC( FF_STAT_FUNC ) },
};
#endif /* ffconfigHAS_FUNCTION_TAB */
#define TPASTE2( a, b ) a ## b
#if ( ffconfigLONG_ERR_MSG != 0 )
/* To get the full error msg: "Not enough memory (malloc( ) returned NULL )" */
#define ERR_ENTRY( M, E ) { M, TPASTE2( FF_ERR_, E ) }
#else
/* To get a shorter msg: "NOT_ENOUGH_MEMORY" */
#define ERR_ENTRY( M, E ) { # E, TPASTE2( FF_ERR_, E ) }
#endif /* ffconfigLONG_ERR_MSG */
const struct _FFERRTAB
{
const char * const strErrorString;
const uint8_t ucErrorCode; /* Currently there are less then 256 errors, so lets keep this table small. */
}
xFreeRTOSFATErrorTable[] =
{
{ "Unknown or Generic Error!", 1 },
ERR_ENTRY( "No Error", NONE ),
ERR_ENTRY( "Null Pointer provided, (probably for IOMAN)", NULL_POINTER ),
ERR_ENTRY( "Not enough memory (malloc() returned NULL)", NOT_ENOUGH_MEMORY ),
ERR_ENTRY( "Device Driver returned a FATAL error!", DEVICE_DRIVER_FAILED ),
ERR_ENTRY( "The blocksize is not 512 multiple", IOMAN_BAD_BLKSIZE ),
ERR_ENTRY( "The memory size, is not a multiple of the blocksize. (Atleast 2 Blocks)", IOMAN_BAD_MEMSIZE ),
ERR_ENTRY( "Device is already registered, use FF_UnregisterBlkDevice() first", IOMAN_DEV_ALREADY_REGD ),
ERR_ENTRY( "No mountable partition was found on the specified device", IOMAN_NO_MOUNTABLE_PARTITION ),
ERR_ENTRY( "The format of the MBR was unrecognised", IOMAN_INVALID_FORMAT ),
ERR_ENTRY( "The provided partition number is out-of-range (0 - 3)", IOMAN_INVALID_PARTITION_NUM ),
ERR_ENTRY( "The selected partition / volume doesn't appear to be FAT formatted", IOMAN_NOT_FAT_FORMATTED ),
ERR_ENTRY( "Cannot register device. (BlkSize not a multiple of 512)", IOMAN_DEV_INVALID_BLKSIZE ),
ERR_ENTRY( "Cannot unregister device, a partition is still mounted", IOMAN_PARTITION_MOUNTED ),
ERR_ENTRY( "Cannot unmount the partition while there are active FILE handles", IOMAN_ACTIVE_HANDLES ),
ERR_ENTRY( "The GPT partition header appears to be corrupt, refusing to mount", IOMAN_GPT_HEADER_CORRUPT ),
ERR_ENTRY( "Disk full", IOMAN_NOT_ENOUGH_FREE_SPACE ),
ERR_ENTRY( "Attempted to Read a sector out of bounds", IOMAN_OUT_OF_BOUNDS_READ ),
ERR_ENTRY( "Attempted to Write a sector out of bounds", IOMAN_OUT_OF_BOUNDS_WRITE ),
ERR_ENTRY( "I/O driver is busy", IOMAN_DRIVER_BUSY ),
ERR_ENTRY( "I/O driver returned fatal error", IOMAN_DRIVER_FATAL_ERROR ),
ERR_ENTRY( "I/O driver returned \"no medium error\"", IOMAN_DRIVER_NOMEDIUM ),
ERR_ENTRY( "Cannot open the file, file already in use", FILE_ALREADY_OPEN ),
ERR_ENTRY( "The specified file could not be found", FILE_NOT_FOUND ),
ERR_ENTRY( "Cannot open a Directory", FILE_OBJECT_IS_A_DIR ),
ERR_ENTRY( "Cannot open for writing: File is marked as Read-Only", FILE_IS_READ_ONLY ),
ERR_ENTRY( "Path not found", FILE_INVALID_PATH ),
ERR_ENTRY( "File operation failed - the file was not opened for writing", FILE_NOT_OPENED_IN_WRITE_MODE ),
ERR_ENTRY( "File operation failed - the file was not opened for reading", FILE_NOT_OPENED_IN_READ_MODE ),
ERR_ENTRY( "File operation failed - could not extend file", FILE_EXTEND_FAILED ),
ERR_ENTRY( "Destination file already exists", FILE_DESTINATION_EXISTS ),
ERR_ENTRY( "Source file was not found", FILE_SOURCE_NOT_FOUND ),
ERR_ENTRY( "Destination path (dir) was not found", FILE_DIR_NOT_FOUND ),
ERR_ENTRY( "Failed to create the directory Entry", FILE_COULD_NOT_CREATE_DIRENT ),
ERR_ENTRY( "A file handle was invalid", FILE_BAD_HANDLE ),
#if ( ffconfigREMOVABLE_MEDIA != 0 )
ERR_ENTRY( "File handle got invalid because media was removed", FILE_MEDIA_REMOVED ),
#endif /* ffconfigREMOVABLE_MEDIA */
ERR_ENTRY( "A file or folder of the same name already exists", DIR_OBJECT_EXISTS ),
ERR_ENTRY( "DIR_DIRECTORY_FULL", DIR_DIRECTORY_FULL ),
ERR_ENTRY( "DIR_END_OF_DIR", DIR_END_OF_DIR ),
ERR_ENTRY( "The directory is not empty", DIR_NOT_EMPTY ),
ERR_ENTRY( "Could not extend File or Folder - No Free Space!", FAT_NO_FREE_CLUSTERS ),
ERR_ENTRY( "Could not find the directory specified by the path", DIR_INVALID_PATH ),
ERR_ENTRY( "The Root Dir is full, and cannot be extended on Fat12 or 16 volumes", DIR_CANT_EXTEND_ROOT_DIR ),
ERR_ENTRY( "Not enough space to extend the directory.", DIR_EXTEND_FAILED ),
ERR_ENTRY( "Name exceeds the number of allowed characters for a filename", DIR_NAME_TOO_LONG ),
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
ERR_ENTRY( "An invalid Unicode character was provided!", UNICODE_INVALID_CODE ),
ERR_ENTRY( "Not enough space in the UTF-16 buffer to encode the entire sequence", UNICODE_DEST_TOO_SMALL ),
ERR_ENTRY( "An invalid UTF-16 sequence was encountered", UNICODE_INVALID_SEQUENCE ),
ERR_ENTRY( "Filename exceeds MAX long-filename length when converted to UTF-16", UNICODE_CONVERSION_EXCEEDED ),
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
};
/**
* @public
* @brief Returns a pointer to a string relating to a FreeRTOS+FAT error code.
*
* @param iErrorCode The error code.
*
* @return Pointer to a string describing the error.
*
**/
const char * FF_GetErrMessage( FF_Error_t iErrorCode )
{
uint32_t stCount = ARRAY_SIZE( xFreeRTOSFATErrorTable );
while( stCount-- )
{
if( ( ( UBaseType_t ) xFreeRTOSFATErrorTable[ stCount ].ucErrorCode ) == FF_GETERROR( iErrorCode ) )
{
break;
}
}
return xFreeRTOSFATErrorTable[ stCount ].strErrorString;
}
const char * FF_GetErrModule( FF_Error_t iErrorCode )
{
uint32_t stCount = ARRAY_SIZE( xFreeRTOSFATModuleTable );
while( stCount-- )
{
if( xFreeRTOSFATModuleTable[ stCount ].ucModuleID == ( uint8_t ) FF_GETMODULE( iErrorCode ) )
{
break;
}
}
return xFreeRTOSFATModuleTable[ stCount ].strModuleName;
}
#if ( ffconfigHAS_FUNCTION_TAB != 0 )
const char * FF_GetErrFunction( FF_Error_t iErrorCode )
{
uint32_t stCount = ARRAY_SIZE( xFreeRTOSFATFunctionTable );
uint16_t ModuleFunc = FF_GETMOD_FUNC( iErrorCode );
static char funcCode[ 32 ];
while( stCount-- != 0 )
{
if( xFreeRTOSFATFunctionTable[ stCount ].ucFunctionID == ModuleFunc )
{
return xFreeRTOSFATFunctionTable[ stCount ].strFunctionName;
}
}
snprintf( funcCode, sizeof( funcCode ), "Func %X", ModuleFunc );
return ( const char * ) funcCode;
}
#endif /* ffconfigHAS_FUNCTION_TAB */
const char * FF_GetErrDescription( FF_Error_t iErrorCode,
char * apBuf,
int aMaxlen )
{
if( FF_isERR( iErrorCode ) )
{
#if ( ffconfigHAS_FUNCTION_TAB != 0 )
snprintf( apBuf, ( size_t ) aMaxlen, "%s::%s::%s",
FF_GetErrModule( iErrorCode ),
FF_GetErrFunction( iErrorCode ),
FF_GetErrMessage( iErrorCode ) );
#else
snprintf( apBuf, ( size_t ) aMaxlen, "%s::%s",
FF_GetErrModule( iErrorCode ),
FF_GetErrMessage( iErrorCode ) );
#endif /* ffconfigHAS_FUNCTION_TAB */
}
else
{
snprintf( apBuf, ( size_t ) aMaxlen, "No error" );
}
return apBuf;
}
#endif /* ffconfigDEBUG != 0 */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,348 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "ff_headers.h"
#include "event_groups.h"
#ifndef configUSE_RECURSIVE_MUTEXES
#error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h
#else
#if ( configUSE_RECURSIVE_MUTEXES != 1 )
#error configUSE_RECURSIVE_MUTEXES must be set to 1 in FreeRTOSConfig.h
#endif
#endif /* configUSE_RECURSIVE_MUTEXES */
#if ( INCLUDE_vTaskDelay != 1 )
#error Missing some FreeRTOS define
#endif
/* There are two areas which are protected with a semaphore:
* Directories and the FAT area.
* The masks below are used when calling Group Event functions. */
#define FF_FAT_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_FAT_LOCK )
#define FF_DIR_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_DIR_LOCK )
/* This is not a real lock: it is a bit (or semaphore) will will be given
* each time when a sector buffer is released. */
#define FF_BUF_LOCK_EVENT_BITS ( ( const EventBits_t ) FF_BUF_LOCK )
#ifndef FF_TIME_TO_WAIT_FOR_EVENT_TICKS
/* The maximum time to wait for a event group bit to come high,
* which gives access to a "critical section": either directories,
* or the FAT. */
#define FF_TIME_TO_WAIT_FOR_EVENT_TICKS pdMS_TO_TICKS( 10000UL )
#endif
/*-----------------------------------------------------------*/
BaseType_t FF_TrySemaphore( void * pxSemaphore,
uint32_t ulTime_ms )
{
BaseType_t xReturn;
/* HT: Actually FF_TrySemaphore is never used. */
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
return 0;
}
configASSERT( pxSemaphore );
xReturn = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, pdMS_TO_TICKS( ulTime_ms ) );
return xReturn;
}
/*-----------------------------------------------------------*/
void FF_PendSemaphore( void * pxSemaphore )
{
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* No need to take the semaphore. */
return;
}
configASSERT( pxSemaphore );
xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) pxSemaphore, portMAX_DELAY );
}
/*-----------------------------------------------------------*/
void FF_ReleaseSemaphore( void * pxSemaphore )
{
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
configASSERT( pxSemaphore );
xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) pxSemaphore );
}
/*-----------------------------------------------------------*/
void FF_Sleep( uint32_t ulTime_ms )
{
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* This sleep is used as a kind of yield.
* Not necessary while the Scheduler does not run. */
return;
}
vTaskDelay( pdMS_TO_TICKS( ulTime_ms ) );
}
/*-----------------------------------------------------------*/
void FF_DeleteEvents( FF_IOManager_t * pxIOManager )
{
if( pxIOManager->xEventGroup != NULL )
{
vEventGroupDelete( pxIOManager->xEventGroup );
}
}
/*-----------------------------------------------------------*/
BaseType_t FF_CreateEvents( FF_IOManager_t * pxIOManager )
{
BaseType_t xResult;
pxIOManager->xEventGroup = xEventGroupCreate();
if( pxIOManager->xEventGroup != NULL )
{
xEventGroupSetBits( pxIOManager->xEventGroup,
FF_FAT_LOCK_EVENT_BITS | FF_DIR_LOCK_EVENT_BITS | FF_BUF_LOCK_EVENT_BITS );
xResult = pdTRUE;
}
else
{
xResult = pdFALSE;
}
return xResult;
}
/*-----------------------------------------------------------*/
void FF_LockDirectory( FF_IOManager_t * pxIOManager )
{
EventBits_t xBits;
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
for( ; ; )
{
/* Called when a task want to make changes to a directory.
* It waits for the desired bit to come high, and clears the
* bit so that other tasks can not take it. */
xBits = xEventGroupWaitBits( pxIOManager->xEventGroup,
FF_DIR_LOCK_EVENT_BITS, /* uxBitsToWaitFor */
pdTRUE, /* xClearOnExit */
pdFALSE, /* xWaitForAllBits n.a. */
FF_TIME_TO_WAIT_FOR_EVENT_TICKS );
if( ( xBits & FF_DIR_LOCK_EVENT_BITS ) != 0 )
{
/* This task has cleared the desired bit.
* It now 'owns' the resource. */
break;
}
}
}
/*-----------------------------------------------------------*/
void FF_UnlockDirectory( FF_IOManager_t * pxIOManager )
{
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_DIR_LOCK_EVENT_BITS ) == 0 );
xEventGroupSetBits( pxIOManager->xEventGroup, FF_DIR_LOCK_EVENT_BITS );
}
/*-----------------------------------------------------------*/
int FF_Has_Lock( FF_IOManager_t * pxIOManager,
uint32_t aBits )
{
int iReturn;
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return 0;
}
void * handle = xTaskGetCurrentTaskHandle();
if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )
{
if( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) )
{
iReturn = pdTRUE;
}
else
{
iReturn = pdFALSE;
}
}
else
{
iReturn = pdFALSE;
}
return iReturn;
}
void FF_Assert_Lock( FF_IOManager_t * pxIOManager,
uint32_t aBits )
{
void * handle;
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
handle = xTaskGetCurrentTaskHandle();
if( ( aBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )
{
configASSERT( ( pxIOManager->pvFATLockHandle != NULL ) && ( pxIOManager->pvFATLockHandle == handle ) );
/* In case configASSERT() is not defined. */
( void ) pxIOManager;
( void ) handle;
}
}
void FF_LockFAT( FF_IOManager_t * pxIOManager )
{
EventBits_t xBits;
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
configASSERT( FF_Has_Lock( pxIOManager, FF_FAT_LOCK ) == pdFALSE );
for( ; ; )
{
/* Called when a task want to make changes to the FAT area.
* It waits for the desired bit to come high, and clears the
* bit so that other tasks can not take it. */
xBits = xEventGroupWaitBits( pxIOManager->xEventGroup,
FF_FAT_LOCK_EVENT_BITS, /* uxBitsToWaitFor */
pdTRUE, /* xClearOnExit */
pdFALSE, /* xWaitForAllBits n.a. */
FF_TIME_TO_WAIT_FOR_EVENT_TICKS );
if( ( xBits & FF_FAT_LOCK_EVENT_BITS ) != 0 )
{
/* This task has cleared the desired bit.
* It now 'owns' the resource. */
pxIOManager->pvFATLockHandle = xTaskGetCurrentTaskHandle();
break;
}
}
}
/*-----------------------------------------------------------*/
void FF_UnlockFAT( FF_IOManager_t * pxIOManager )
{
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
configASSERT( ( xEventGroupGetBits( pxIOManager->xEventGroup ) & FF_FAT_LOCK_EVENT_BITS ) == 0 );
pxIOManager->pvFATLockHandle = NULL;
xEventGroupSetBits( pxIOManager->xEventGroup, FF_FAT_LOCK_EVENT_BITS );
}
/*-----------------------------------------------------------*/
BaseType_t FF_BufferWait( FF_IOManager_t * pxIOManager,
uint32_t xWaitMS )
{
EventBits_t xBits;
BaseType_t xReturn;
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return pdTRUE;
}
/* This function is called when a task is waiting for a sector buffer
* to become available. Each time when a sector buffer becomes available,
* the bit will be set ( see FF_BufferProceed() here below ). */
xBits = xEventGroupWaitBits( pxIOManager->xEventGroup,
FF_BUF_LOCK_EVENT_BITS, /* uxBitsToWaitFor */
pdTRUE, /* xClearOnExit */
pdFALSE, /* xWaitForAllBits n.a. */
pdMS_TO_TICKS( xWaitMS ) );
if( ( xBits & FF_BUF_LOCK_EVENT_BITS ) != 0 )
{
xReturn = pdTRUE;
}
else
{
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
void FF_BufferProceed( FF_IOManager_t * pxIOManager )
{
if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
{
/* Scheduler not yet active. */
return;
}
/* Wake-up a task that is waiting for a sector buffer to become available. */
xEventGroupSetBits( pxIOManager->xEventGroup, FF_BUF_LOCK_EVENT_BITS );
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,117 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_memory.c
* @ingroup MEMORY
*
* @defgroup MEMORY FreeRTOS+FAT Memory Access Routines
* @brief Handles memory access in a portable way.
*
* Provides simple, fast, and portable access to memory routines.
* These are only used to read data from buffers. That are LITTLE ENDIAN
* due to the FAT specification.
*
* These routines may need to be modified to your platform.
*
**/
#include "ff_headers.h"
/*
* Here below 3 x 2 access functions that allow the code
* not to worry about the endianness of the MCU.
*/
#if ( ffconfigINLINE_MEMORY_ACCESS == 0 )
uint8_t FF_getChar( const uint8_t * pBuffer,
uint32_t aOffset )
{
return ( uint8_t ) ( pBuffer[ aOffset ] );
}
uint16_t FF_getShort( const uint8_t * pBuffer,
uint32_t aOffset )
{
FF_T_UN16 u16;
pBuffer += aOffset;
u16.bytes.u8_1 = pBuffer[ 1 ];
u16.bytes.u8_0 = pBuffer[ 0 ];
return u16.u16;
}
uint32_t FF_getLong( const uint8_t * pBuffer,
uint32_t aOffset )
{
FF_T_UN32 u32;
pBuffer += aOffset;
u32.bytes.u8_3 = pBuffer[ 3 ];
u32.bytes.u8_2 = pBuffer[ 2 ];
u32.bytes.u8_1 = pBuffer[ 1 ];
u32.bytes.u8_0 = pBuffer[ 0 ];
return u32.u32;
}
void FF_putChar( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value )
{
pBuffer[ aOffset ] = ( uint8_t ) Value;
}
void FF_putShort( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value )
{
FF_T_UN16 u16;
u16.u16 = ( uint16_t ) Value;
pBuffer += aOffset;
pBuffer[ 0 ] = u16.bytes.u8_0;
pBuffer[ 1 ] = u16.bytes.u8_1;
}
void FF_putLong( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value )
{
FF_T_UN32 u32;
u32.u32 = Value;
pBuffer += aOffset;
pBuffer[ 0 ] = u32.bytes.u8_0;
pBuffer[ 1 ] = u32.bytes.u8_1;
pBuffer[ 2 ] = u32.bytes.u8_2;
pBuffer[ 3 ] = u32.bytes.u8_3;
}
#endif /* if ( ffconfigINLINE_MEMORY_ACCESS == 0 ) */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,784 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_string.c
* @ingroup STRING
*
* @defgroup STRING FreeRTOS+FAT String Library
* @brief Portable String Library for FreeRTOS+FAT
*
*
**/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "ff_headers.h"
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
#include <wchar.h>
#include <wctype.h>
#endif
/*
* These will eventually be moved into a platform independent string
* library. Which will be optional. (To allow the use of system specific versions).
*/
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
void FF_cstrntowcs( FF_T_WCHAR * wcsDest,
const char * szpSource,
uint32_t ulLength )
{
while( ( *szpSource != '\0' ) && ( ulLength-- != 0 ) )
{
*( wcsDest++ ) = *( szpSource++ );
}
*wcsDest = '\0';
}
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/*-----------------------------------------------------------*/
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
void FF_cstrtowcs( FF_T_WCHAR * wcsDest,
const char * szpSource )
{
while( *szpSource != '\0' )
{
*wcsDest++ = ( FF_T_WCHAR ) *( szpSource++ );
}
*wcsDest = '\0';
}
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/*-----------------------------------------------------------*/
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
void FF_wcstocstr( char * szpDest,
const FF_T_WCHAR * wcsSource )
{
while( *wcsSource != '\0' )
{
*szpDest++ = ( int8_t ) *( wcsSource++ );
}
*szpDest = '\0';
}
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/*-----------------------------------------------------------*/
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
void FF_wcsntocstr( char * szpDest,
const FF_T_WCHAR * wcsSource,
uint32_t ulLength )
{
while( ( *wcsSource != '\0' ) && ( ulLength-- != 0 ) )
{
*( szpDest++ ) = ( int8_t ) *( wcsSource++ );
}
*szpDest = '\0';
}
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/*-----------------------------------------------------------*/
/*-----------------------------------------------------------*/
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
void FF_toupper( FF_T_WCHAR * string,
uint32_t ulLength )
{
uint32_t i;
for( i = 0; i < ulLength; i++ )
{
string[ i ] = towupper( string[ i ] );
}
}
/*-----------------------------------------------------------*/
void FF_tolower( FF_T_WCHAR * string,
uint32_t ulLength )
{
uint32_t i;
for( i = 0; i < ulLength; i++ )
{
string[ i ] = towlower( string[ i ] );
}
}
/*-----------------------------------------------------------*/
#else /* ffconfigUNICODE_UTF16_SUPPORT */
void FF_toupper( char * string,
uint32_t ulLength )
{
uint32_t i;
for( i = 0; i < ulLength; i++ )
{
if( ( string[ i ] >= 'a' ) && ( string[ i ] <= 'z' ) )
{
string[ i ] -= 32;
}
if( string[ i ] == '\0' )
{
break;
}
}
}
/*-----------------------------------------------------------*/
void FF_tolower( char * string,
uint32_t ulLength )
{
uint32_t i;
for( i = 0; i < ulLength; i++ )
{
if( ( string[ i ] >= 'A' ) && ( string[ i ] <= 'Z' ) )
{
string[ i ] += 32;
}
if( string[ i ] == '\0' )
{
break;
}
}
}
/*-----------------------------------------------------------*/
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/**
* @private
* @brief Compares 2 strings for the specified length, and returns pdTRUE is they are identical
* otherwise pdFALSE is returned.
*
**/
#if ( ffconfigUNICODE_UTF16_SUPPORT == 0 )
BaseType_t FF_strmatch( const char * str1,
const char * str2,
BaseType_t xLength )
{
register BaseType_t i;
register char char1, char2;
if( xLength == 0 )
{
xLength = strlen( str1 );
if( xLength != ( BaseType_t ) strlen( str2 ) )
{
return pdFALSE;
}
}
for( i = 0; i < xLength; i++ )
{
char1 = str1[ i ];
char2 = str2[ i ];
if( ( char1 >= 'A' ) && ( char1 <= 'Z' ) )
{
char1 += 32;
}
if( ( char2 >= 'A' ) && ( char2 <= 'Z' ) )
{
char2 += 32;
}
if( char1 != char2 )
{
return pdFALSE;
}
}
return pdTRUE;
}
#else /* ffconfigUNICODE_UTF16_SUPPORT */
BaseType_t FF_strmatch( const FF_T_WCHAR * str1,
const FF_T_WCHAR * str2,
BaseType_t xLength )
{
register BaseType_t i;
register FF_T_WCHAR char1, char2;
if( xLength == 0 )
{
xLength = wcslen( str1 );
if( xLength != wcslen( str2 ) )
{
return pdFALSE;
}
}
for( i = 0; i < xLength; i++ )
{
char1 = towlower( str1[ i ] );
char2 = towlower( str2[ i ] );
if( char1 != char2 )
{
return pdFALSE;
}
}
return pdTRUE;
}
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/**
* @private
* @brief A re-entrant Strtok function. No documentation is provided :P
* Use at your own risk. (This is for FreeRTOS+FAT's use only).
**/
#if ( ffconfigUNICODE_UTF16_SUPPORT == 0 )
char * FF_strtok( const char * string,
char * token,
uint16_t * tokenNumber,
BaseType_t * last,
BaseType_t xLength )
{
uint16_t i, y, tokenStart, tokenEnd = 0;
i = 0;
y = 0;
if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) )
{
i++;
}
tokenStart = i;
while( i < xLength )
{
if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) )
{
y++;
if( y == *tokenNumber )
{
tokenStart = ( uint16_t ) ( i + 1 );
}
if( y == ( *tokenNumber + 1 ) )
{
tokenEnd = i;
break;
}
}
i++;
}
if( tokenEnd == 0 )
{
if( *last == pdTRUE )
{
return NULL;
}
else
{
*last = pdTRUE;
}
tokenEnd = i;
}
if( ( tokenEnd - tokenStart ) < ffconfigMAX_FILENAME )
{
memcpy( token, ( string + tokenStart ), ( uint32_t ) ( tokenEnd - tokenStart ) );
token[ tokenEnd - tokenStart ] = '\0';
}
else
{
memcpy( token, ( string + tokenStart ), ( uint32_t ) ( ffconfigMAX_FILENAME ) );
token[ ffconfigMAX_FILENAME - 1 ] = '\0';
}
/*token[tokenEnd - tokenStart] = '\0'; */
*tokenNumber += 1;
return token;
}
#else /* ffconfigUNICODE_UTF16_SUPPORT */
FF_T_WCHAR * FF_strtok( const FF_T_WCHAR * string,
FF_T_WCHAR * token,
uint16_t * tokenNumber,
BaseType_t * last,
BaseType_t xLength )
{
uint16_t i, y, tokenStart, tokenEnd = 0;
i = 0;
y = 0;
if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) )
{
i++;
}
tokenStart = i;
while( i < xLength )
{
if( ( string[ i ] == '\\' ) || ( string[ i ] == '/' ) )
{
y++;
if( y == *tokenNumber )
{
tokenStart = ( uint16_t ) ( i + 1 );
}
if( y == ( *tokenNumber + 1 ) )
{
tokenEnd = i;
break;
}
}
i++;
}
if( tokenEnd == 0 )
{
if( *last == pdTRUE )
{
return NULL;
}
else
{
*last = pdTRUE;
}
tokenEnd = i;
}
if( ( tokenEnd - tokenStart ) < ffconfigMAX_FILENAME )
{
memcpy( token, ( string + tokenStart ), ( uint32_t ) ( tokenEnd - tokenStart ) * sizeof( FF_T_WCHAR ) );
token[ tokenEnd - tokenStart ] = '\0';
}
else
{
memcpy( token, ( string + tokenStart ), ( uint32_t ) ( ffconfigMAX_FILENAME ) * sizeof( FF_T_WCHAR ) );
token[ ffconfigMAX_FILENAME - 1 ] = '\0';
}
/*token[tokenEnd - tokenStart] = '\0'; */
*tokenNumber += 1;
return token;
}
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/* UTF-8 Routines */
/*
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
* 0000 0000-0000 007F 0xxxxxxx
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
*
* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
*/
#if ( ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
UBaseType_t FF_GetUtf16SequenceLen( uint16_t usLeadChar )
{
UBaseType_t uxReturn;
if( ( usLeadChar & 0xFC00 ) == 0xD800 )
{
uxReturn = 2;
}
else
{
uxReturn = 1;
}
return uxReturn;
} /* FF_GetUtf16SequenceLen() */
#endif /* if ( ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 ) */
/*-----------------------------------------------------------*/
/*
* Returns the number of UTF-8 units read.
* Will not exceed ulSize UTF-16 units. (ulSize * 2 bytes).
*/
/*
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
* 0000 0000-0000 007F 0xxxxxxx
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
*
* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx -- We don't encode these because we won't receive them. (Invalid UNICODE).
*/
#if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
int32_t FF_Utf8ctoUtf16c( uint16_t * utf16Dest,
const uint8_t * utf8Source,
uint32_t ulSize )
{
uint32_t ulUtf32char;
uint16_t utf16Source = 0;
register int32_t lSequenceNumber = 0;
/* Count number of set bits before a zero. */
while( ( ( *utf8Source != '\0' ) & ( 0x80 >> ( lSequenceNumber ) ) ) )
{
lSequenceNumber++;
}
if( lSequenceNumber == 0UL )
{
lSequenceNumber++;
}
if( ulSize == 0UL )
{
/* Returned value becomes an error, with the highest bit set. */
lSequenceNumber = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF8CTOUTF16C;
}
else
{
switch( lSequenceNumber )
{
case 1:
utf16Source = ( uint16_t ) *utf8Source;
memcpy( utf16Dest, &utf16Source, sizeof( uint16_t ) );
break;
case 2:
utf16Source = ( uint16_t ) ( ( *utf8Source & 0x1F ) << 6 ) | ( ( *( utf8Source + 1 ) & 0x3F ) );
memcpy( utf16Dest, &utf16Source, sizeof( uint16_t ) );
break;
case 3:
utf16Source = ( uint16_t ) ( ( *utf8Source & 0x0F ) << 12 ) | ( ( *( utf8Source + 1 ) & 0x3F ) << 6 ) | ( ( *( utf8Source + 2 ) & 0x3F ) );
memcpy( utf16Dest, &utf16Source, sizeof( uint16_t ) );
break;
case 4:
if( ulSize < 2 )
{
/* Returned value becomes an error. */
lSequenceNumber = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF8CTOUTF16C;
}
else
{
/* Convert to UTF-32 and then into UTF-16 */
ulUtf32char = ( uint16_t )
( ( *utf8Source & 0x0F ) << 18 ) |
( ( *( utf8Source + 1 ) & 0x3F ) << 12 ) |
( ( *( utf8Source + 2 ) & 0x3F ) << 6 ) |
( ( *( utf8Source + 3 ) & 0x3F ) );
utf16Source = ( uint16_t ) ( ( ( ulUtf32char - 0x10000 ) & 0xFFC00 ) >> 10 ) | 0xD800;
memcpy( utf16Dest, &utf16Source, sizeof( uint16_t ) );
utf16Source = ( uint16_t ) ( ( ( ulUtf32char - 0x10000 ) & 0x003FF ) >> 00 ) | 0xDC00;
memcpy( utf16Dest + 1, &utf16Source, sizeof( uint16_t ) );
}
break;
default:
break;
}
}
return lSequenceNumber;
} /* FF_Utf8ctoUtf16c() */
#endif /* ffconfigUNICODE_UTF8_SUPPORT */
/*-----------------------------------------------------------*/
/*
* Returns the number of UTF-8 units required to encode the UTF-16 sequence.
* Will not exceed ulSize UTF-8 units. (ulSize * 1 bytes).
*/
#if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
int32_t FF_Utf16ctoUtf8c( uint8_t * utf8Dest,
const uint16_t * utf16Source,
uint32_t ulSize )
{
uint32_t ulUtf32char;
uint16_t ulUtf16char;
int32_t lReturn = 0L;
do
{
if( ulSize == 0UL )
{
lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C;
break;
}
memcpy( &ulUtf16char, utf16Source, sizeof( uint16_t ) );
/* A surrogate sequence was encountered. Must transform to UTF32 first. */
if( ( ulUtf16char & 0xF800 ) == 0xD800 )
{
ulUtf32char = ( ( uint32_t ) ( ulUtf16char & 0x003FF ) << 10 ) + 0x10000;
memcpy( &ulUtf16char, utf16Source + 1, sizeof( uint16_t ) );
if( ( ulUtf16char & 0xFC00 ) != 0xDC00 )
{
/* Invalid UTF-16 sequence. */
lReturn = FF_ERR_UNICODE_INVALID_SEQUENCE | FF_UTF16CTOUTF8C;
break;
}
ulUtf32char |= ( ( uint32_t ) ( ulUtf16char & 0x003FF ) );
}
else
{
ulUtf32char = ( uint32_t ) ulUtf16char;
}
/* Now convert to the UTF-8 sequence. */
/* Single byte UTF-8 sequence. */
if( ulUtf32char < 0x00000080 )
{
*( utf8Dest + 0 ) = ( uint8_t ) ulUtf32char;
lReturn = 1;
break;
}
/* Double byte UTF-8 sequence. */
if( ulUtf32char < 0x00000800 )
{
if( ulSize < 2 )
{
lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C;
}
else
{
*( utf8Dest + 0 ) = ( uint8_t ) ( 0xC0 | ( ( ulUtf32char >> 6 ) & 0x1F ) );
*( utf8Dest + 1 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 0 ) & 0x3F ) );
lReturn = 2;
}
break;
}
/* Triple byte UTF-8 sequence. */
if( ulUtf32char < 0x00010000 )
{
if( ulSize < 3 )
{
lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C;
}
else
{
*( utf8Dest + 0 ) = ( uint8_t ) ( 0xE0 | ( ( ulUtf32char >> 12 ) & 0x0F ) );
*( utf8Dest + 1 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 6 ) & 0x3F ) );
*( utf8Dest + 2 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 0 ) & 0x3F ) );
lReturn = 3;
}
break;
}
/* Quadruple byte UTF-8 sequence. */
if( ulUtf32char < 0x00200000 )
{
if( ulSize < 4 )
{
lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF16CTOUTF8C;
}
else
{
*( utf8Dest + 0 ) = ( uint8_t ) ( 0xF0 | ( ( ulUtf32char >> 18 ) & 0x07 ) );
*( utf8Dest + 1 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 12 ) & 0x3F ) );
*( utf8Dest + 2 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 6 ) & 0x3F ) );
*( utf8Dest + 3 ) = ( uint8_t ) ( 0x80 | ( ( ulUtf32char >> 0 ) & 0x3F ) );
lReturn = 4;
}
break;
}
lReturn = FF_ERR_UNICODE_INVALID_CODE | FF_UTF16CTOUTF8C; /* Invalid Character */
}
while( pdFALSE );
return lReturn;
} /* FF_Utf16ctoUtf8c() */
#endif /* ffconfigUNICODE_UTF8_SUPPORT */
/*-----------------------------------------------------------*/
/* UTF-16 Support Functions */
/* Converts a UTF-32 Character into its equivalent UTF-16 sequence. */
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF )
int32_t FF_Utf32ctoUtf16c( uint16_t * utf16Dest,
uint32_t utf32char,
uint32_t ulSize )
{
int32_t lReturn;
/* Check that its a valid UTF-32 wide-char! */
/* This range is not a valid Unicode code point. */
if( ( utf32char >= 0xD800 ) && ( utf32char <= 0xDFFF ) )
{
lReturn = FF_ERR_UNICODE_INVALID_CODE | FF_UTF32CTOUTF16C; /* Invalid character. */
}
else if( utf32char < 0x10000 )
{
*utf16Dest = ( uint16_t ) utf32char; /* Simple conversion! Char comes within UTF-16 space (without surrogates). */
lReturn = 1;
}
else if( ulSize < 2 )
{
lReturn = FF_ERR_UNICODE_DEST_TOO_SMALL | FF_UTF32CTOUTF16C; /* Not enough UTF-16 units to record this character. */
}
else if( utf32char < 0x00200000 )
{
/* Conversion to a UTF-16 Surrogate pair! */
/*valueImage = utf32char - 0x10000; */
*( utf16Dest + 0 ) = ( uint16_t ) ( ( ( utf32char - 0x10000 ) & 0xFFC00 ) >> 10 ) | 0xD800;
*( utf16Dest + 1 ) = ( uint16_t ) ( ( ( utf32char - 0x10000 ) & 0x003FF ) >> 00 ) | 0xDC00;
lReturn = 2; /* Surrogate pair encoded value. */
}
else
{
/* Invalid Character */
lReturn = FF_ERR_UNICODE_INVALID_CODE | FF_UTF32CTOUTF16C;
}
return lReturn;
} /* FF_Utf32ctoUtf16c() */
#endif /* #if( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) */
/*-----------------------------------------------------------*/
/* Converts a UTF-16 sequence into its equivalent UTF-32 code point. */
#if ( ffconfigNOT_USED_FOR_NOW != 0 )
int32_t FF_Utf16ctoUtf32c( uint32_t * utf32Dest,
const uint16_t * utf16Source )
{
int32_t lReturn;
/*Not a surrogate sequence. */
if( ( *utf16Source & 0xFC00 ) != 0xD800 )
{
*utf32Dest = ( uint32_t ) *utf16Source;
lReturn = 1; /* A single UTF-16 item was used to represent the character. */
}
else
{
*utf32Dest = ( ( uint32_t ) ( *( utf16Source + 0 ) & 0x003FF ) << 10 ) + 0x10000;
if( ( *( utf16Source + 1 ) & 0xFC00 ) != 0xDC00 )
{
lReturn = FF_ERR_UNICODE_INVALID_SEQUENCE | FF_UTF16CTOUTF32C; /* Invalid UTF-16 sequence. */
}
else
{
*utf32Dest |= ( ( uint32_t ) ( *( utf16Source + 1 ) & 0x003FF ) );
lReturn = 2; /* 2 utf-16 units make up the Unicode code-point. */
}
}
return lReturn;
} /* FF_Utf16ctoUtf32c() */
#endif /* ffconfigNOT_USED_FOR_NOW */
/*-----------------------------------------------------------*/
/*
* Returns the total number of UTF-16 items required to represent
* the provided UTF-32 string in UTF-16 form.
*/
/*
* UBaseType_t FF_Utf32GetUtf16Len( const uint32_t *utf32String )
* {
* UBaseType_t utf16len = 0;
*
* while( *utf32String )
* {
* if( *utf32String++ <= 0xFFFF )
* {
* utf16len++;
* }
* else
* {
* utf16len += 2;
* }
* }
*
* return utf16len;
* }
*/
/*-----------------------------------------------------------*/
/* String conversions */
#if ( ffconfigNOT_USED_FOR_NOW != 0 )
int32_t FF_Utf32stoUtf8s( uint8_t * Utf8String,
uint32_t * Utf32String )
{
int i = 0, y = 0;
uint16_t utf16buffer[ 2 ];
while( Utf32String[ i ] != '\0' )
{
/* Convert to a UTF16 char. */
FF_Utf32ctoUtf16c( utf16buffer, Utf32String[ i ], 2 );
/* Now convert the UTF16 to UTF8 sequence. */
y += FF_Utf16ctoUtf8c( &Utf8String[ y ], utf16buffer, 4 );
i++;
}
Utf8String[ y ] = '\0';
return 0;
} /* FF_Utf32stoUtf8s() */
#endif /* ffconfigNOT_USED_FOR_NOW */
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,286 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#include <stdio.h>
#include <string.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "portable.h"
#include "ff_headers.h"
#include "ff_sys.h"
#ifndef ARRAY_SIZE
#define ARRAY_SIZE( x ) ( int ) ( sizeof( x ) / sizeof( x )[ 0 ] )
#endif
/*
* Define a collection of 'file systems' as a simple array
*/
typedef struct xSYSTEM
{
FF_SubSystem_t xSystems[ ffconfigMAX_FILE_SYS ];
volatile BaseType_t xFileSystemCount;
} ff_sys_t;
static ff_sys_t file_systems;
static const char rootDir[] = "/";
int FF_FS_Count( void )
{
return ( int ) file_systems.xFileSystemCount;
}
/*-----------------------------------------------------------*/
void FF_FS_Init( void )
{
memset( &file_systems, '\0', sizeof( file_systems ) );
/* There is always a root file system, even if it doesn't have a
* IO manager. */
file_systems.xFileSystemCount = ( BaseType_t ) 1;
/* Set to "/", second byte is already zero. */
file_systems.xSystems[ 0 ].pcPath[ 0 ] = ( char ) '/';
file_systems.xSystems[ 0 ].xPathlen = 1;
}
/*-----------------------------------------------------------*/
int FF_FS_Add( const char * pcPath,
FF_Disk_t * pxDisk )
{
int iReturn = pdFALSE;
configASSERT( pxDisk );
if( *pcPath != ( char ) '/' )
{
FF_PRINTF( "FF_FS_Add: Need a \"/\": '%s'\n", pcPath );
}
else
{
BaseType_t xUseIndex = -1;
size_t uxPathLength = strlen( pcPath );
vTaskSuspendAll();
{
if( file_systems.xFileSystemCount == ( BaseType_t ) 0 )
{
FF_FS_Init();
}
if( uxPathLength == ( size_t ) 1u )
{
/* This is the "/" path
* and will always be put at index 0 */
xUseIndex = ( BaseType_t ) 0;
}
else
{
BaseType_t xIndex, xFreeIndex = -1;
FF_SubSystem_t * pxSubSystem = file_systems.xSystems + 1; /* Skip the root entry */
for( xIndex = ( BaseType_t ) 1; xIndex < file_systems.xFileSystemCount; xIndex++, pxSubSystem++ )
{
if( ( pxSubSystem->xPathlen == ( BaseType_t ) uxPathLength ) &&
( memcmp( pxSubSystem->pcPath, pcPath, uxPathLength ) == 0 ) )
{
/* A system is updated with a new handler. */
xUseIndex = xIndex;
break;
}
if( ( pxSubSystem->pxManager == NULL ) && ( xFreeIndex < 0 ) )
{
/* Remember the first free slot. */
xFreeIndex = xIndex;
}
}
if( xUseIndex < ( BaseType_t ) 0 )
{
if( xFreeIndex >= ( BaseType_t ) 0 )
{
/* Use the first free slot. */
xUseIndex = xFreeIndex;
}
else if( file_systems.xFileSystemCount < ARRAY_SIZE( file_systems.xSystems ) )
{
/* Fill a new entry. */
xUseIndex = file_systems.xFileSystemCount++;
}
}
} /* uxPathLength != 1 */
if( xUseIndex >= ( BaseType_t ) 0 )
{
iReturn = pdTRUE;
strncpy( file_systems.xSystems[ xUseIndex ].pcPath, pcPath, sizeof( file_systems.xSystems[ xUseIndex ].pcPath ) );
file_systems.xSystems[ xUseIndex ].xPathlen = uxPathLength;
file_systems.xSystems[ xUseIndex ].pxManager = pxDisk->pxIOManager;
}
}
xTaskResumeAll();
if( iReturn == pdFALSE )
{
FF_PRINTF( "FF_FS_Add: Table full '%s' (max = %d)\n", pcPath, ( int ) ARRAY_SIZE( file_systems.xSystems ) );
}
}
return iReturn;
}
/*-----------------------------------------------------------*/
void FF_FS_Remove( const char * pcPath )
{
BaseType_t xUseIndex, xIndex;
size_t uxPathLength;
if( pcPath[ 0 ] == ( char ) '/' )
{
xUseIndex = -1;
uxPathLength = strlen( pcPath );
/* Is it the "/" path ? */
if( uxPathLength == ( size_t ) 1u )
{
xUseIndex = 0;
}
else
{
FF_SubSystem_t * pxSubSystem = file_systems.xSystems + 1;
for( xIndex = 1; xIndex < file_systems.xFileSystemCount; xIndex++, pxSubSystem++ )
{
if( ( pxSubSystem->xPathlen == ( BaseType_t ) uxPathLength ) &&
( memcmp( pxSubSystem->pcPath, pcPath, uxPathLength ) == 0 ) )
{
xUseIndex = xIndex;
break;
}
}
}
if( xUseIndex >= 0 )
{
vTaskSuspendAll();
{
file_systems.xSystems[ xUseIndex ].pxManager = NULL;
file_systems.xSystems[ xUseIndex ].xPathlen = ( BaseType_t ) 0;
for( xIndex = file_systems.xFileSystemCount - 1; xIndex > 0; xIndex-- )
{
if( file_systems.xSystems[ xIndex ].pxManager != NULL )
{
/* The slot at 'xIndex' is still in use. */
break;
}
}
file_systems.xFileSystemCount = xIndex + 1;
}
xTaskResumeAll();
}
}
}
/*-----------------------------------------------------------*/
int FF_FS_Find( const char * pcPath,
FF_DirHandler_t * pxHandler )
{
FF_SubSystem_t * pxSubSystem;
size_t uxPathLength;
BaseType_t xUseIndex;
int iReturn;
pxSubSystem = file_systems.xSystems + 1;
uxPathLength = strlen( pcPath );
memset( pxHandler, '\0', sizeof( *pxHandler ) );
for( xUseIndex = 1; xUseIndex < file_systems.xFileSystemCount; xUseIndex++, pxSubSystem++ )
{
if( ( uxPathLength >= ( size_t ) pxSubSystem->xPathlen ) &&
( memcmp( pxSubSystem->pcPath, pcPath, ( size_t ) pxSubSystem->xPathlen ) == 0 ) &&
( ( pcPath[ pxSubSystem->xPathlen ] == '\0' ) || ( pcPath[ pxSubSystem->xPathlen ] == '/' ) ) ) /* System "/ram" should not match with "/ramc/etc". */
{
if( pcPath[ pxSubSystem->xPathlen ] == '\0' )
{
pxHandler->pcPath = rootDir;
}
else
{
pxHandler->pcPath = pcPath + pxSubSystem->xPathlen;
}
pxHandler->pxManager = pxSubSystem->pxManager;
break;
}
}
if( xUseIndex == file_systems.xFileSystemCount )
{
pxHandler->pcPath = pcPath;
pxHandler->pxManager = file_systems.xSystems[ 0 ].pxManager;
}
if( FF_Mounted( pxHandler->pxManager ) )
{
iReturn = pdTRUE;
}
else
{
iReturn = pdFALSE;
}
return iReturn;
}
/*-----------------------------------------------------------*/
int FF_FS_Get( int xIndex,
FF_SubSystem_t * pxSystem )
{
int iReturn;
/* Get a copy of a fs info. */
if( ( xIndex < 0 ) || ( xIndex >= file_systems.xFileSystemCount ) )
{
iReturn = pdFALSE;
}
else
{
/* Note: it will copy the contents of 'FF_SubSystem_t'. */
*pxSystem = file_systems.xSystems[ xIndex ];
iReturn = pdTRUE;
}
return iReturn;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,302 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#include <stdio.h>
#include <time.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "ff_time.h"
/**
* @file ff_time.c
* @ingroup TIME
*
* @defgroup TIME Real-Time Clock Interface
* @brief Allows FreeRTOS+FAT to time-stamp files.
*
* Provides a means for receiving the time on any platform.
**/
#if ( ffconfigTIME_SUPPORT != 0 ) /* This if-block spans the rest of the source file. */
/**
* @public
* @brief Populates an FF_SystemTime_t object with the current time from the system.
*
* The developer must modify this function so that it is suitable for their platform.
* The function must return with 0, and if the time is not available all elements of the
* FF_SystemTime_t object must be zero'd, as in the examples provided.
*
* @param pxTime Pointer to an FF_TIME object.
*
* @return Always returns 0.
**/
int32_t FF_GetSystemTime( FF_SystemTime_t * pxTime )
{
FF_TimeStruct_t xTimeStruct;
/* Fetch the current time. */
time_t secs = FreeRTOS_time( NULL );
/* Fill the fields in 'xTimeStruct'. */
FreeRTOS_gmtime_r( &secs, &xTimeStruct );
pxTime->Hour = xTimeStruct.tm_hour;
pxTime->Minute = xTimeStruct.tm_min;
pxTime->Second = xTimeStruct.tm_sec;
pxTime->Day = xTimeStruct.tm_mday;
pxTime->Month = xTimeStruct.tm_mon + 1;
pxTime->Year = xTimeStruct.tm_year + 1900;
return 0;
} /* FF_GetSystemTime() */
/*-----------------------------------------------------------*/
/*
* FreeRTOS+FAT
* Time conversion functions:
*
* FF_TimeStruct_t *FreeRTOS_gmtime_r( const time_t *pxTime, FF_TimeStruct_t *pxTimeBuf )
* time_t FreeRTOS_mktime(FF_TimeStruct_t *pxTimeBuf)
*/
#define GMTIME_FIRST_YEAR ( 1970 )
#define TM_STRUCT_FIRST_YEAR ( 1900 )
#define SECONDS_PER_MINUTE ( 60 )
#define MINUTES_PER_HOUR ( 60 )
#define HOURS_PER_DAY ( 24 )
#define SECONDS_PER_HOUR ( MINUTES_PER_HOUR * SECONDS_PER_MINUTE )
#define SECONDS_PER_DAY ( HOURS_PER_DAY * SECONDS_PER_HOUR )
/* The first weekday in 'FF_TimeStruct_t' is Sunday. */
#define WEEK_DAY_SUNDAY 0
#define WEEK_DAY_MONNDAY 1
#define WEEK_DAY_TUESDAY 2
#define WEEK_DAY_WEDNESDAY 3
#define WEEK_DAY_THURSDAY 4
#define WEEK_DAY_FRIDAY 5
#define WEEK_DAY_SATURDAY 6
/* Make a bitmask with a '1' for each 31-day month. */
#define _MM( month ) ( 1u << ( month - 1 ) )
#define MASK_LONG_MONTHS ( _MM( 1 ) | _MM( 3 ) | _MM( 5 ) | _MM( 7 ) | _MM( 8 ) | _MM( 10 ) | _MM( 12 ) )
#define DAYS_UNTIL_1970 ( ( 1970 * 365 ) + ( 1970 / 4 ) - ( 1970 / 100 ) + ( 1970 / 400 ) )
#define DAYS_BEFORE_MARCH ( 59 )
static portINLINE int iIsLeapyear( int iYear )
{
int iReturn;
if( ( iYear % 4 ) != 0 )
{
/* Not a multiple of 4 years. */
iReturn = pdFALSE;
}
else if( ( iYear % 400 ) == 0 )
{
/* Every 4 centuries there is a leap year */
iReturn = pdTRUE;
}
else if( ( iYear % 100 ) == 0 )
{
/* Other centuries are not a leap year */
iReturn = pdFALSE;
}
else
{
/* Otherwise every fourth year. */
iReturn = pdTRUE;
}
return iReturn;
}
static portINLINE unsigned long ulDaysPerYear( int iYear )
{
int iDays;
if( iIsLeapyear( iYear ) )
{
iDays = 366;
}
else
{
iDays = 365;
}
return iDays;
}
static int iDaysPerMonth( int iYear,
int iMonth )
{
int iDays;
/* Month is zero-based, 1 is February. */
if( iMonth != 1 )
{
/* 30 or 31 days? */
if( ( MASK_LONG_MONTHS & ( 1u << iMonth ) ) != 0 )
{
iDays = 31;
}
else
{
iDays = 30;
}
}
else if( iIsLeapyear( iYear ) == pdFALSE )
{
/* February, non leap year. */
iDays = 28;
}
else
{
/* February, leap year. */
iDays = 29;
}
return iDays;
}
FF_TimeStruct_t * FreeRTOS_gmtime_r( const time_t * pxTime,
FF_TimeStruct_t * pxTimeBuf )
{
time_t xTime = *pxTime;
unsigned long ulDaySeconds, ulDayNumber;
int iYear = GMTIME_FIRST_YEAR;
int iMonth;
/* Clear all fields, some might not get set here. */
memset( ( void * ) pxTimeBuf, '\0', sizeof( *pxTimeBuf ) );
/* Seconds since last midnight. */
ulDaySeconds = ( unsigned long ) ( xTime % SECONDS_PER_DAY );
/* Days since 1 Jan 1970. */
ulDayNumber = ( unsigned long ) ( xTime / SECONDS_PER_DAY );
/* Today's HH:MM:SS */
pxTimeBuf->tm_hour = ulDaySeconds / SECONDS_PER_HOUR;
pxTimeBuf->tm_min = ( ulDaySeconds % SECONDS_PER_HOUR ) / 60;
pxTimeBuf->tm_sec = ulDaySeconds % 60;
/* Today's week day, knowing that 1-1-1970 was a THursday. */
pxTimeBuf->tm_wday = ( ulDayNumber + WEEK_DAY_THURSDAY ) % 7;
for( ; ; )
{
/* Keep subtracting 365 (or 366) days while possible. */
unsigned long ulDays = ulDaysPerYear( iYear );
if( ulDayNumber < ulDays )
{
break;
}
ulDayNumber -= ulDays;
iYear++;
}
/* Subtract 1900. */
pxTimeBuf->tm_year = iYear - TM_STRUCT_FIRST_YEAR;
/* The day within this year. */
pxTimeBuf->tm_yday = ulDayNumber;
/* Month are counted as 0..11 */
iMonth = 0;
for( ; ; )
{
unsigned long ulDays = iDaysPerMonth( iYear, iMonth );
/* Keep subtracting 30 (or 28, 29, or 31) days while possible. */
if( ulDayNumber < ulDays )
{
break;
}
ulDayNumber -= ulDays;
iMonth++;
}
pxTimeBuf->tm_mon = iMonth;
/* Month days are counted as 1..31 */
pxTimeBuf->tm_mday = ulDayNumber + 1;
return pxTimeBuf;
}
time_t FreeRTOS_mktime( const FF_TimeStruct_t * pxTimeBuf )
{
/* Get year AD. */
int iYear = 1900 + pxTimeBuf->tm_year; /* 20xx */
/* Get month zero-based. */
int iMonth = pxTimeBuf->tm_mon; /* 0..11 */
uint32_t ulDays;
uint32_t ulResult;
ulDays = pxTimeBuf->tm_mday - 1; /* 1..31 */
/* Make March the first month. */
iMonth -= 2;
if( iMonth < 0 )
{
/* January or February: leap day has yet to come for this year. */
iYear--;
iMonth += 12;
}
/* Add the number of days past until this month. */
ulDays += ( ( 306 * iMonth ) + 5 ) / 10;
/* Add days past before this year: */
ulDays +=
+( iYear * 365 ) /* Every normal year. */
+ ( iYear / 4 ) /* Plus a day for every leap year. */
- ( iYear / 100 ) /* Minus the centuries. */
+ ( iYear / 400 ) /* Except every fourth century. */
- ( DAYS_UNTIL_1970 ) /* Minus the days before 1-1-1970 */
+ ( DAYS_BEFORE_MARCH ); /* Because 2 months were subtracted. */
ulResult =
( ulDays * SECONDS_PER_DAY ) +
( pxTimeBuf->tm_hour * SECONDS_PER_HOUR ) +
( pxTimeBuf->tm_min * SECONDS_PER_MINUTE ) +
pxTimeBuf->tm_sec;
return ulResult;
}
#endif /* ffconfigTIME_SUPPORT */

View File

@ -0,0 +1,202 @@
/*
*FreeRTOS+FAT is an open source,
*thread aware and scalable FAT12/FAT16/FAT32 DOS/Windows compatible embedded FAT file system which was recently acquired by Real Time Engineers ltd.
*for use with and without the RTOS.
*FreeRTOS+FAT is already used in commercial products,
*and is the file system used in the FTP and HTTP server examples that are documented on the FreeRTOS+TCP pages.
*The standard C library style API includes a thread local errno value, and the lower level native API provides a rich set of detailed error codes.
*We are currently working hard on improving the embedded file systems documentation,
*adding additional scalability options, and updating the source code to ensure it conforms with our strict coding standards.
*We encourage you to download FreeRTOS+FAT to try the embedded FAT file system for yourself while we continue this work.
*Applications that use FreeRTOS+FAT must provide a FreeRTOSFATConfig.h header file in which the parameters described on this page can be defined:
***/
#ifndef FF_FATCONFIG_H
#define FF_FATCONFIG_H
#include <stdio.h>
#define portINLINE inline
#define FF_PRINTF printf
/*Must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN,
depending on the endian of the architecture on which FreeRTOS is running.*/
//大小端
#define ffconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN
/*Set to 1 to maintain a current working directory (CWD) for each task that accesses the file system, allowing relative paths to be used.
Set to 0 not to use a CWD, in which case full paths must be used for each file access.*/
//维护当前目录
#define ffconfigHAS_CWD 0
/*Set to an index within FreeRTOSs thread local storage array that is free for use by FreeRTOS+FAT.
FreeRTOS+FAT will use two consecutive indexes from this that set by ffconfigCWD_THREAD_LOCAL_INDEX.
The number of thread local storage pointers provided by FreeRTOS is set by configNUM_THREAD_LOCAL_STORAGE_POINTERS in FreeRTOSConfig.h.*/
//本地线程数组索引
#define ffconfigCWD_THREAD_LOCAL_INDEX 0
/*Set to 1 to include long file name support. Set to 0 to exclude long file name support.
If long file name support is excluded then only 8.3 file names can be used. Long file names will be recognised, but ignored.
Users should familiarise themselves with any patent issues that may potentially exist around the use of long file names in FAT file systems before enabling long file name support.*/
//长文件名
#define ffconfigLFN_SUPPORT 1
/*Only used when ffconfigLFN_SUPPORT is set to 1.
Set to 1 to include a files short name when listing a directory, i.e. when calling findfirst()/findnext().
The short name will be stored in the pcShortName field of FF_DIRENT.
Set to 0 to only include a files long name.*/
//短文件名
#define ffconfigINCLUDE_SHORT_NAME 0
/*Set to 1 to recognise and apply the case bits used by Windows XP+
when using short file names storing file names such as “readme.TXT” or “SETUP.exe” in a short-name entry.
This is the recommended setting for maximum compatibility.
Set to 0 to ignore the case bits.*/
#define ffconfigSHORTNAME_CASE 0
/*Only used when ffconfigLFN_SUPPORT is set to 1.
Set to 1 to use UTF-16 (wide-characters) for file and directory names.
Set to 0 to use either 8-bit ASCII or UTF-8 for file and directory names (see the ffconfigUNICODE_UTF8_SUPPORT).*/
#define ffconfigUNICODE_UTF16_SUPPORT 0
/*Only used when ffconfigLFN_SUPPORT is set to 1.
Set to 1 to use UTF-8 encoding for file and directory names.
Set to 0 to use either 8-bit ASCII or UTF-16 for file and directory names (see the ffconfig_UTF_16_SUPPORT setting).*/
#define ffconfigUNICODE_UTF8_SUPPORT 0
/*Set to 1 to include FAT12 support.
Set to 0 to exclude FAT12 support.
FAT16 and FAT32 are always enabled.*/
#define ffconfigFAT12_SUPPORT 0
/*When writing and reading data, i/o becomes less efficient if sizes other than 512 bytes are being used.
When set to 1 each file handle will allocate a 512-byte character buffer to facilitate “unaligned access”.*/
//当写入和读取数据时如果使用的大小不是512字节i/o的效率就会降低。当设置为1时每个文件句柄将分配一个512字节的字符缓冲区以促进“非对齐访问”。
#define ffconfigOPTIMISE_UNALIGNED_ACCESS 0
/*Input and output to a disk uses buffers that are only flushed at the following times:
When a new buffer is needed and no other buffers are available.
When opening a buffer in READ mode for a sector that has just been changed.
After creating, removing or closing a file or a directory.
Normally this is quick enough and it is efficient.
If ffconfigCACHE_WRITE_THROUGH is set to 1 then buffers will also be flushed each time a buffer is released which is less efficient but more secure.*/
//如果设置为1那么缓冲区也将在每次释放缓冲区时被刷新—这样效率较低但更安全。
#define ffconfigCACHE_WRITE_THROUGH 1
/*In most cases, the FAT table has two identical copies on the disk, allowing the second copy to be used in the case of a read error.
If Set to 1 to use both FATs this is less efficient but more secure.
Set to 0 to use only one FAT the second FAT will never be written to.*/
#define ffconfigWRITE_BOTH_FATS 1
/*Set to 1 to have the number of free clusters and the first free cluster to be written to the FS info sector each time one of those values changes.
Set to 0 not to store these values in the FS info sector, making booting slower, but making changes faster.*/
#define ffconfigWRITE_FREE_COUNT 1
/*Set to 1 to maintain file and directory time stamps for creation, modify and last access.
Set to 0 to exclude time stamps.
If time support is used, the following function must be supplied:
time_t FreeRTOS_time( time_t *pxTime );
FreeRTOS_time has the same semantics as the standard time() function.*/
#define ffconfigTIME_SUPPORT 0
/*Set to 1 if the media is removable (such as a memory card).
Set to 0 if the media is not removable.
When set to 1 all file handles will be “invalidated” if the media is extracted.
If set to 0 then file handles will not be invalidated.
In that case the user will have to confirm that the media is still present before every access.*/
//如果介质是可移动的(如存储卡)则设置为1。
#define ffconfigREMOVABLE_MEDIA 1
/*Set to 1 to determine the disks free space and the disks first free cluster when a disk is mounted.
Set to 0 to find these two values when they are first needed. Determining the values can take some time.*/
#define ffconfigMOUNT_FIND_FREE 1
/*Set to 1 to trust the contents of the ulLastFreeCluster and ulFreeClusterCount fields.
Set to 0 not to trust these fields.*/
#define ffconfigFSINFO_TRUSTED 1
/*Set to 1 to store recent paths in a cache,
enabling much faster access when the path is deep within a directory structure at the expense of additional RAM usage.
Set to 0 to not use a path cache.*/
#define ffconfigPATH_CACHE 1
/*Only used if ffconfigPATH_CACHE is 1.
Sets the maximum number of paths that can exist in the patch cache at any one time.*/
#define ffconfigPATH_CACHE_DEPTH 8
/*Set to 1 to calculate a HASH value for each existing short file name.
Use of HASH values can improve performance when working with large directories, or with files that have a similar name.
Set to 0 not to calculate a HASH value.*/
#define ffconfigHASH_CACHE 0
#define ffconfigHASH_CACHE_DEPTH 2
/*Only used if ffconfigHASH_CACHE is set to 1
Set to CRC8 or CRC16 to use 8-bit or 16-bit HASH values respectively.*/
#define ffconfigHASH_FUNCTION CRC16
/*Set to 1 to add a parameter to ff_mkdir() that allows an entire directory tree to be created in one go,
rather than having to create one directory in the tree at a time.
For example mkdir( “/etc/settings/network”, pdTRUE );.
Set to 0 to use the normal mkdir() semantics (without the additional parameter).*/
//可创建目录树
#define ffconfigMKDIR_RECURSIVE 1
/*Set to 1 for each call to fnReadBlocks and fnWriteBlocks to be performed with a semphore lock.
Set to 0 for each call to fnReadBlocks and fnWriteBlocks not to use an additional semaphore.*/
//#define ffconfigBLKDEV_USES_SEM 0
/*Set to a function that will be used for all dynamic memory allocations.
Setting to pvPortMalloc() will use the same memory allocator as FreeRTOS.
For example: #define ffconfigMALLOC( size ) pvPortMalloc( size )*/
#define ffconfigMALLOC( size ) pvPortMalloc( size )
/*Set to a function that matches the above allocator defined with ffconfigMALLOC.
Setting to vPortFree() will use the same memory free function as FreeRTOS.
For example: #define ffconfigFREE( ptr ) vPortFree( ptr )*/
#define ffconfigFREE( ptr ) vPortFree( ptr )
/*Set to 1 to calculate the free size and volume size as a 64-bit number.
Set to 0 to calculate these values as a 32-bit number.*/
#define ffconfig64_NUM_SUPPORT 1
/*Defines the maximum number of partitions (and also logical partitions) that can be recognised.*/
#define ffconfigMAX_PARTITIONS 4
/*Defines how many drives can be combined in total. Should be set to at least 2.*/
#define ffconfigMAX_FILE_SYS 4
/*In case the low-level driver returns an error FF_ERR_DRIVER_BUSY,
the library will pause for a number of ms, defined in ffconfigDRIVER_BUSY_SLEEP_MS before re-trying.*/
#define ffconfigDRIVER_BUSY_SLEEP_MS 20
/*Set to 1 to include the ff_fprintf() function in the build.
Set to 0 to exclude the ff_fprintf() function from the build.
ff_fprintf() is quite a heavy function because it allocates RAM and brings in a lot of string and variable argument handling code.
If ff_fprintf() is not being used then the code size can be reduced by setting ffconfigFPRINTF_SUPPORT to 0.*/
#define ffconfigFPRINTF_SUPPORT 1
/*ff_fprintf() will allocate a buffer of this size in which it will create its formatted string. The buffer will be freed before the function exits.*/
#define ffconfigFPRINTF_BUFFER_LENGTH 128
/*Set to 1 to inline some internal memory access functions.
Set to 0 not to use inline memory access functions.*/
#define ffconfigINLINE_MEMORY_ACCESS 0
/*Officially the only criteria to determine the FAT type (12, 16, or 32 bits) is the total number of clusters:
if( ulNumberOfClusters < 4085 ) : Volume is FAT12
if( ulNumberOfClusters < 65525 ) : Volume is FAT16
if( ulNumberOfClusters >= 65525 ) : Volume is FAT32
Not every formatted device follows the above rule.
Set to 1 to perform additional checks over and above inspecting the number of clusters on a disk to determine the FAT type.
Set to 0 to only look at the number of clusters on a disk to determine the FAT type.*/
#define ffconfigFAT_CHECK 1
/*Sets the maximum length for file names,
including the path. Note that the value of this define is directly related to the maximum stack use of the +FAT library.
In some APIs, a character buffer of size ffconfigMAX_FILENAME will be declared on stack.*/
//#define ffconfigMAX_FILENAME (49+1)
#define ffconfigMAX_FILENAME (79+1)
#define ffconfigMIN_CLUSTERS_FAT16 1024//2048
#endif

View File

@ -0,0 +1,463 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef FF_DEFAULTCONFIG_H
/* The error numbers defined in this file will be moved to the core FreeRTOS
* code in future versions of FreeRTOS - at which time the following header file
* will be removed. */
#include "FreeRTOS_errno_FAT.h"
#if !defined( ffconfigBYTE_ORDER )
/* Must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN,
* depending on the endian of the architecture on which FreeRTOS is running. */
#error Invalid FreeRTOSFATConfig.h file: ffconfigBYTE_ORDER must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN
#endif
#if ( ffconfigBYTE_ORDER != pdFREERTOS_LITTLE_ENDIAN ) && ( ffconfigBYTE_ORDER != pdFREERTOS_BIG_ENDIAN )
#error Invalid FreeRTOSFATConfig.h file: ffconfigBYTE_ORDER must be set to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN
#endif
#if ( pdFREERTOS_LITTLE_ENDIAN != 0 ) || ( pdFREERTOS_BIG_ENDIAN != 1 )
#error Invalid projdefs.h or FreeRTOS_errno_FAT.h file
#endif
#if !defined( ffconfigHAS_CWD )
/* Set to 1 to maintain a current working directory (CWD) for each task that
* accesses the file system, allowing relative paths to be used.
*
* Set to 0 not to use a CWD, in which case full paths must be used for each
* file access. */
#define ffconfigHAS_CWD 0
#if !defined( ffconfigCWD_THREAD_LOCAL_INDEX )
#error ffconfigCWD_THREAD_LOCAL_INDEX must be set to a free position within FreeRTOSs thread local storage pointer array for storage of a pointer to the CWD structure.
#endif
#endif
#if !defined( ffconfigLFN_SUPPORT )
/* Set to 1 to include long file name support. Set to 0 to exclude long
* file name support.
*
* If long file name support is excluded then only 8.3 file names can be used.
* Long file names will be recognised but ignored.
*
* Users should familiarise themselves with any patent issues that may
* potentially exist around the use of long file names in FAT file systems
* before enabling long file name support. */
#define ffconfigLFN_SUPPORT 0
#endif
#if !defined( ffconfigINCLUDE_SHORT_NAME )
/* Only used when ffconfigLFN_SUPPORT is set to 1.
*
* Set to 1 to include a file's short name when listing a directory, i.e. when
* calling findfirst()/findnext(). The short name will be stored in the
* 'pcShortName' field of FF_DirEnt_t.
*
* Set to 0 to only include a file's long name. */
#define ffconfigINCLUDE_SHORT_NAME 0
#endif
#if !defined( ffconfigSHORTNAME_CASE )
/* Set to 1 to recognise and apply the case bits used by Windows XP+ when
* using short file names - storing file names such as "readme.TXT" or
* "SETUP.exe" in a short-name entry. This is the recommended setting for
* maximum compatibility.
*
* Set to 0 to ignore the case bits. */
#define ffconfigSHORTNAME_CASE 0
#endif
#if !defined( ipconfigQUICK_SHORT_FILENAME_CREATION )
/* This method saves a lot of time when creating directories with
* many similar file names: when the short name version of a LFN already
* exists, try at most 3 entries with a tilde:
* README~1.TXT
* README~2.TXT
* README~3.TXT
* After that create entries with pseudo-random 4-digit hex digits:
* REA~E7BB.TXT
* REA~BA32.TXT
* REA~D394.TXT
*/
#define ipconfigQUICK_SHORT_FILENAME_CREATION 1
#endif
/* ASCII versus UNICODE, UTF-16 versus UTF-8 :
* FAT directories, when using Long File Names, always store file and directory
* names UTF-16 encoded.
* The user can select how these names must be represented internally:
* - ASCII (default)
* - UTF-8 (ffconfigUNICODE_UTF8_SUPPORT = 1)
* - UTF-16 (ffconfigUNICODE_UTF16_SUPPORT = 1)
*/
#if ( ffconfigUNICODE_UTF16_SUPPORT == 0 )
/* Only used when ffconfigLFN_SUPPORT is set to 1.
*
* Set to 1 to use UTF-16 (wide-characters) for file and directory names.
*
* Set to 0 to use either 8-bit ASCII or UTF-8 for file and directory names
* (see the ffconfigUNICODE_UTF8_SUPPORT). */
#define ffconfigUNICODE_UTF16_SUPPORT 0
#endif
#if !defined( ffconfigUNICODE_UTF8_SUPPORT )
/* Only used when ffconfigLFN_SUPPORT is set to 1.
*
* Set to 1 to use UTF-8 encoding for file and directory names.
*
* Set to 0 to use either 8-bit ASCII or UTF-16 for file and directory
* names (see the ffconfig_UTF_16_SUPPORT setting). */
#define ffconfigUNICODE_UTF8_SUPPORT 0
#endif
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
#error Can not use both UTF-16 and UTF-8
#endif
#if !defined( ffconfigFAT12_SUPPORT )
/* Set to 1 to include FAT12 support.
*
* Set to 0 to exclude FAT12 support.
*
* FAT16 and FAT32 are always enabled. */
#define ffconfigFAT12_SUPPORT 0
#endif
#if !defined( ffconfigOPTIMISE_UNALIGNED_ACCESS )
/* When writing and reading data, i/o becomes less efficient if sizes other
* than the sector size (usually 512 bytes) are being used. When set to 1, each file handle will
* allocate a one sector size character buffer to facilitate "unaligned access". */
#define ffconfigOPTIMISE_UNALIGNED_ACCESS 0
#endif
#if !defined( ffconfigCACHE_WRITE_THROUGH )
/* Input and output to a disk uses buffers that are only flushed at the
* following times:
*
* - When a new buffer is needed and no other buffers are available.
* - When opening a buffer in READ mode for a sector that has just been changed.
* - After creating, removing or closing a file or a directory.
*
* Normally this is quick enough and it is efficient. If
* ffconfigCACHE_WRITE_THROUGH is set to 1 then buffers will also be flushed each
* time a buffer is released - which is less efficient but more secure. */
#define ffconfigCACHE_WRITE_THROUGH 0
#endif
#if !defined( ffconfigWRITE_BOTH_FATS )
/* In most cases, the FAT table has two identical copies on the disk,
* allowing the second copy to be used in the case of a read error. If
*
* Set to 1 to use both FATs - this is less efficient but more secure.
*
* Set to 0 to use only one FAT - the second FAT will never be written to. */
#define ffconfigWRITE_BOTH_FATS 0
#endif
#if !defined( ffconfigWRITE_FREE_COUNT )
/* Set to 1 to have the number of free clusters and the first free cluster
* to be written to the FS info sector each time one of those values changes.
*
* Set to 0 not to store these values in the FS info sector, making booting
* slower, but making changes faster. */
#define ffconfigWRITE_FREE_COUNT 0
#endif
#if !defined( ffconfigTIME_SUPPORT )
/* Set to 1 to maintain file and directory time stamps for creation, modify
* and last access.
*
* Set to 0 to exclude time stamps.
*
* If time support is used, the following function must be supplied:
*
* time_t FreeRTOS_time( time_t *pxTime );
*
* FreeRTOS_time has the same semantics as the standard time() function. */
#define ffconfigTIME_SUPPORT 0
#endif
#if !defined( ffconfigREMOVABLE_MEDIA )
/* Set to 1 if the media is removable (such as a memory card).
*
* Set to 0 if the media is not removable.
*
* When set to 1 all file handles will be "invalidated" if the media is
* extracted. If set to 0 then file handles will not be invalidated.
* In that case the user will have to confirm that the media is still present
* before every access. */
#define ffconfigREMOVABLE_MEDIA 0
#endif
#if !defined( ffconfigMOUNT_FIND_FREE )
/* Set to 1 to determine the disk's free space and the disk's first free
* cluster when a disk is mounted.
*
* Set to 0 to find these two values when they are first needed. Determining
* the values can take some time. */
#define ffconfigMOUNT_FIND_FREE 0
#endif
#if !defined( ffconfigFSINFO_TRUSTED )
/* Set to 1 to 'trust' the contents of the 'ulLastFreeCluster' and
* ulFreeClusterCount fields.
*
* Set to 0 not to 'trust' these fields.*/
#define ffconfigFSINFO_TRUSTED 0
#endif
#if !defined( ffconfigFINDAPI_ALLOW_WILDCARDS )
/* For now must be set to 0. */
#define ffconfigFINDAPI_ALLOW_WILDCARDS 0
#endif
#if !defined( ffconfigWILDCARD_CASE_INSENSITIVE )
/* For now must be set to 0. */
#define ffconfigWILDCARD_CASE_INSENSITIVE 0
#endif
#if !defined( ffconfigPATH_CACHE )
/* Set to 1 to store recent paths in a cache, enabling much faster access
* when the path is deep within a directory structure at the expense of
* additional RAM usage.
*
* Set to 0 to not use a path cache. */
#define ffconfigPATH_CACHE 0
#endif
#if !defined( ffconfigPATH_CACHE_DEPTH )
/* Only used if ffconfigPATH_CACHE is 1.
*
* Sets the maximum number of paths that can exist in the patch cache at any
* one time. */
#define ffconfigPATH_CACHE_DEPTH 5
#endif
#if !defined( ffconfigHASH_CACHE )
/* Set to 1 to calculate a HASH value for each existing short file name.
* Use of HASH values can improve performance when working with large
* directories, or with files that have a similar name.
*
* Set to 0 not to calculate a HASH value. */
#define ffconfigHASH_CACHE 0
#endif
#if ( ffconfigHASH_CACHE != 0 )
#if !defined( ffconfigHASH_FUNCTION )
/* Only used if ffconfigHASH_CACHE is set to 1
*
* Set to CRC8 or CRC16 to use 8-bit or 16-bit HASH values respectively. */
#define ffconfigHASH_FUNCTION CRC16
#endif
#if ffconfigHASH_FUNCTION == CRC16
#define ffconfigHASH_TABLE_SIZE 8192
#elif ffconfigHASH_FUNCTION == CRC8
#define ffconfigHASH_TABLE_SIZE 32
#else
#error Invalid Hashing function selected. CRC16 or CRC8. See your FreeRTOSFATConfig.h.
#endif
#endif /* ffconfigHASH_CACHE != 0 */
#if !defined( ffconfigMKDIR_RECURSIVE )
/* Set to 1 to add a parameter to ff_mkdir() that allows an entire directory
* tree to be created in one go, rather than having to create one directory in
* the tree at a time. For example mkdir( "/etc/settings/network", pdTRUE );.
*
* Set to 0 to use the normal mkdir() semantics (without the additional
* parameter). */
#define ffconfigMKDIR_RECURSIVE 0
#endif
#if !defined( ffconfigMALLOC )
/* Set to a function that will be used for all dynamic memory allocations.
* Setting to pvPortMalloc() will use the same memory allocator as FreeRTOS. */
#define ffconfigMALLOC( size ) pvPortMalloc( size )
#endif
#if !defined( ffconfigFREE )
/* Set to a function that matches the above allocator defined with
* ffconfigMALLOC. Setting to vPortFree() will use the same memory free
* function as FreeRTOS. */
#define ffconfigFREE( ptr ) vPortFree( ptr )
#endif
#if !defined( ffconfig64_NUM_SUPPORT )
/* Set to 1 to calculate the free size and volume size as a 64-bit number.
*
* Set to 0 to calculate these values as a 32-bit number. */
#define ffconfig64_NUM_SUPPORT 0
#endif
#if !defined( ffconfigMAX_PARTITIONS )
/* Defines the maximum number of partitions (and also logical partitions)
* that can be recognised. */
#define ffconfigMAX_PARTITIONS 4
#endif
#if !defined( ffconfigMAX_FILE_SYS )
/* Defines how many drives can be combined in total. Should be set to at
* least 2. */
#define ffconfigMAX_FILE_SYS 4
#endif
#if !defined( ffconfigDRIVER_BUSY_SLEEP_MS )
/* In case the low-level driver returns an error 'FF_ERR_DRIVER_BUSY',
* the library will pause for a number of ms, defined in
* ffconfigDRIVER_BUSY_SLEEP_MS before re-trying. */
#define ffconfigDRIVER_BUSY_SLEEP_MS 20
#endif
#if !defined( ffconfigFPRINTF_SUPPORT )
/* Set to 1 to include the ff_fprintf() function.
*
* Set to 0 to exclude the ff_fprintf() function.
*
* ff_fprintf() is quite a heavy function because it allocates RAM and
* brings in a lot of string and variable argument handling code. If
* ff_fprintf() is not being used then the code size can be reduced by setting
* ffconfigFPRINTF_SUPPORT to 0. */
#define ffconfigFPRINTF_SUPPORT 0
#endif
#if !defined( ffconfigFPRINTF_BUFFER_LENGTH )
/* ff_fprintf() will allocate a buffer of this size in which it will create
* its formatted string. The buffer will be freed before the function
* exits. */
#define ffconfigFPRINTF_BUFFER_LENGTH 128
#endif
#if !defined( ffconfigDEBUG )
#define ffconfigDEBUG 0
#endif
#if !defined( ffconfigLONG_ERR_MSG )
#define ffconfigLONG_ERR_MSG 0
#endif
#if ( ffconfigDEBUG != 0 )
#if !defined( ffconfigHAS_FUNCTION_TAB )
#define ffconfigHAS_FUNCTION_TAB 1
#endif
#endif
#if !defined( ffconfigINLINE_MEMORY_ACCESS )
/* Set to 1 to inline some internal memory access functions.
*
* Set to 0 to not inline the memory access functions. */
#define ffconfigINLINE_MEMORY_ACCESS 0
#endif
#if !defined( ffconfigMIRROR_FATS_UMOUNT )
/*_RB_ not sure. */
#define ffconfigMIRROR_FATS_UMOUNT 0
#endif
#if !defined( ffconfigFAT_CHECK )
/* Officially the only criteria to determine the FAT type (12, 16, or 32
* bits) is the total number of clusters:
* if( ulNumberOfClusters < 4085 ) : Volume is FAT12
* if( ulNumberOfClusters < 65525 ) : Volume is FAT16
* if( ulNumberOfClusters >= 65525 ) : Volume is FAT32
* Not every formatted device follows the above rule.
*
* Set to 1 to perform additional checks over and above inspecting the
* number of clusters on a disk to determine the FAT type.
*
* Set to 0 to only look at the number of clusters on a disk to determine the
* FAT type. */
#define ffconfigFAT_CHECK 0
#endif
#if !defined( ffconfigMAX_FILENAME )
/* Sets the maximum length for file names, including the path.
* Note that the value of this define is directly related to the maximum stack
* use of the +FAT library. In some API's, a character buffer of size
* 'ffconfigMAX_FILENAME' will be declared on stack. */
#define ffconfigMAX_FILENAME 129
#endif
#if !defined( ffconfigUSE_DELTREE )
/* By default, do not include the recursive function ff_deltree() as
* recursion breaches the coding standard - USE WITH CARE. */
#define ffconfigUSE_DELTREE 0
#endif
#if !defined( ffconfigFILE_EXTEND_FLUSHES_BUFFERS )
/* When writing large files, the contents of the FAT entries will be flushed
* after every call to FF_Write(). This flushing can be inhibited, by defining
* ffconfigFILE_EXTEND_FLUSHES_BUFFERS as 0. */
#define ffconfigFILE_EXTEND_FLUSHES_BUFFERS 1
#endif
#if !defined( FF_PRINTF )
#define FF_PRINTF FF_PRINTF
static portINLINE void FF_PRINTF( const char * pcFormat,
... )
{
( void ) pcFormat;
}
#endif
#endif /* ifndef FF_DEFAULTCONFIG_H */

View File

@ -0,0 +1,87 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef FREERTOS_ERRNO_FAT
#define FREERTOS_ERRNO_FAT
/* The following definitions will be included in the core FreeRTOS code in
* future versions of FreeRTOS - hence the 'pd' (ProjDefs) prefix - at which time
* this file will be removed. */
/* The following errno values are used by FreeRTOS+ components, not FreeRTOS
* itself. */
/* For future compatibility (see comment above), check the definitions have not
* already been made. */
#ifndef pdFREERTOS_ERRNO_NONE
#define pdFREERTOS_ERRNO_NONE 0 /* No errors */
#define pdFREERTOS_ERRNO_ENOENT 2 /* No such file or directory */
#define pdFREERTOS_ERRNO_EIO 5 /* I/O error */
#define pdFREERTOS_ERRNO_ENXIO 6 /* No such device or address */
#define pdFREERTOS_ERRNO_EBADF 9 /* Bad file number */
#define pdFREERTOS_ERRNO_EAGAIN 11 /* No more processes */
#define pdFREERTOS_ERRNO_EWOULDBLOCK 11 /* Operation would block */
#define pdFREERTOS_ERRNO_ENOMEM 12 /* Not enough memory */
#define pdFREERTOS_ERRNO_EACCES 13 /* Permission denied */
#define pdFREERTOS_ERRNO_EFAULT 14 /* Bad address */
#define pdFREERTOS_ERRNO_EBUSY 16 /* Mount device busy */
#define pdFREERTOS_ERRNO_EEXIST 17 /* File exists */
#define pdFREERTOS_ERRNO_EXDEV 18 /* Cross-device link */
#define pdFREERTOS_ERRNO_ENODEV 19 /* No such device */
#define pdFREERTOS_ERRNO_ENOTDIR 20 /* Not a directory */
#define pdFREERTOS_ERRNO_EISDIR 21 /* Is a directory */
#define pdFREERTOS_ERRNO_EINVAL 22 /* Invalid argument */
#define pdFREERTOS_ERRNO_ENOSPC 28 /* No space left on device */
#define pdFREERTOS_ERRNO_ESPIPE 29 /* Illegal seek */
#define pdFREERTOS_ERRNO_EROFS 30 /* Read only file system */
#define pdFREERTOS_ERRNO_EUNATCH 42 /* Protocol driver not attached */
#define pdFREERTOS_ERRNO_EBADE 50 /* Invalid exchange */
#define pdFREERTOS_ERRNO_EFTYPE 79 /* Inappropriate file type or format */
#define pdFREERTOS_ERRNO_ENMFILE 89 /* No more files */
#define pdFREERTOS_ERRNO_ENOTEMPTY 90 /* Directory not empty */
#define pdFREERTOS_ERRNO_ENAMETOOLONG 91 /* File or path name too long */
#define pdFREERTOS_ERRNO_EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define pdFREERTOS_ERRNO_ENOBUFS 105 /* No buffer space available */
#define pdFREERTOS_ERRNO_ENOPROTOOPT 109 /* Protocol not available */
#define pdFREERTOS_ERRNO_EADDRINUSE 112 /* Address already in use */
#define pdFREERTOS_ERRNO_ETIMEDOUT 116 /* Connection timed out */
#define pdFREERTOS_ERRNO_EINPROGRESS 119 /* Connection already in progress */
#define pdFREERTOS_ERRNO_EALREADY 120 /* Socket already connected */
#define pdFREERTOS_ERRNO_EADDRNOTAVAIL 125 /* Address not available */
#define pdFREERTOS_ERRNO_EISCONN 127 /* Socket is already connected */
#define pdFREERTOS_ERRNO_ENOTCONN 128 /* Socket is not connected */
#define pdFREERTOS_ERRNO_ENOMEDIUM 135 /* No medium inserted */
#define pdFREERTOS_ERRNO_EILSEQ 138 /* An invalid UTF-16 sequence was encountered. */
#define pdFREERTOS_ERRNO_ECANCELED 140 /* Operation canceled. */
/* The following endian values are used by FreeRTOS+ components, not FreeRTOS
* itself. */
#define pdFREERTOS_LITTLE_ENDIAN 0
#define pdFREERTOS_BIG_ENDIAN 1
#endif /* pdFREERTOS_ERRNO_NONE */
#endif /* FREERTOS_ERRNO_FAT */

View File

@ -0,0 +1,45 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_crc.h
* @ingroup CRC
*
**/
#ifndef _FF_CRC_H_
#define _FF_CRC_H_
uint8_t FF_GetCRC8( uint8_t * pbyData,
uint32_t stLength );
uint16_t FF_GetCRC16( uint8_t * pbyData,
uint32_t stLength );
uint32_t FF_GetCRC32( uint8_t * pbyData,
uint32_t stLength );
extern const uint32_t crc32_table[ 256 ];
#endif /* ifndef _FF_CRC_H_ */

View File

@ -0,0 +1,74 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_devices.h
**/
#ifndef FF_DEVICES_H
#define FF_DEVICES_H
#ifndef PLUS_FAT_H
#error this header will be included from "ff_headers.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define FF_DEV_NO_DEV 0
#define FF_DEV_CHAR_DEV 1
#define FF_DEV_BLOCK_DEV 2
BaseType_t xCheckDevicePath( const char * pcPath );
int FF_Device_Seek( FF_FILE * pxStream,
long lOffset,
int iWhence );
BaseType_t FF_Device_Open( const char * pcPath,
FF_FILE * pxStream );
void FF_Device_Close( FF_FILE * pxStream );
size_t FF_Device_Read( void * pvBuf,
size_t lSize,
size_t lCount,
FF_FILE * pxStream );
size_t FF_Device_Write( const void * pvBuf,
size_t lSize,
size_t lCount,
FF_FILE * pxStream );
int FF_Device_GetDirEnt( const char * pcPath,
FF_DirEnt_t * pxDirEnt );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* FF_DEVICES_H */

View File

@ -0,0 +1,274 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_dir.h
* @ingroup DIR
**/
#ifndef _FF_DIR_H_
#define _FF_DIR_H_
#ifndef PLUS_FAT_H
#error this header will be included from "ff_headers.h"
#endif
#define FIND_FLAG_SHORTNAME_SET 0x01u
#define FIND_FLAG_SHORTNAME_CHECKED 0x02u
#define FIND_FLAG_SHORTNAME_FOUND 0x04u
#define FIND_FLAG_FITS_SHORT 0x08u
#define FIND_FLAG_SIZE_OK 0x10u
#define FIND_FLAG_CREATE_FLAG 0x20u
#define FIND_FLAG_FITS_SHORT_OK ( FIND_FLAG_FITS_SHORT | FIND_FLAG_SIZE_OK )
typedef struct
{
uint32_t ulChainLength;
uint32_t ulDirCluster;
uint32_t ulCurrentClusterLCN;
uint32_t ulCurrentClusterNum;
FF_Buffer_t * pxBuffer;
} FF_FetchContext_t;
typedef struct
{
uint32_t ulFileSize;
uint32_t ulObjectCluster;
/* Book Keeping. */
uint32_t ulCurrentCluster;
uint32_t ulAddrCurrentCluster;
uint32_t ulDirCluster;
uint16_t usCurrentItem;
/* End Book Keeping. */
#if ( ffconfigTIME_SUPPORT != 0 )
FF_SystemTime_t xCreateTime; /* Date and Time Created. */
FF_SystemTime_t xModifiedTime; /* Date and Time Modified. */
FF_SystemTime_t xAccessedTime; /* Date of Last Access. */
#endif
#if ( ffconfigFINDAPI_ALLOW_WILDCARDS != 0 )
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_T_WCHAR pcWildCard[ ffconfigMAX_FILENAME ];
#else
char pcWildCard[ ffconfigMAX_FILENAME ];
#endif
BaseType_t xInvertWildCard;
#endif
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_T_WCHAR pcFileName[ ffconfigMAX_FILENAME ];
#else
char pcFileName[ ffconfigMAX_FILENAME ];
#endif
#if ( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 )
char pcShortName[ 13 ];
#endif
uint8_t ucAttrib;
#if ( ffconfigDEV_SUPPORT != 0 )
uint8_t ucIsDeviceDir;
#endif
FF_FetchContext_t xFetchContext;
} FF_DirEnt_t;
/*
* Some public API's, i.e. they're used but ff_stdio.c
*/
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_Error_t FF_FindFirst( FF_IOManager_t * pxIOManager,
FF_DirEnt_t * pxDirent,
const FF_T_WCHAR * pcPath );
FF_Error_t FF_MkDir( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * pcPath );
#else
FF_Error_t FF_FindFirst( FF_IOManager_t * pxIOManager,
FF_DirEnt_t * pxDirent,
const char * pcPath );
FF_Error_t FF_MkDir( FF_IOManager_t * pxIOManager,
const char * pcPath );
#endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
FF_Error_t FF_FindNext( FF_IOManager_t * pxIOManager,
FF_DirEnt_t * pxDirent );
static portINLINE void FF_RewindFind( FF_DirEnt_t * pxDirent )
{
pxDirent->usCurrentItem = 0;
}
/*
* Some API's internal to the +FAT library.
*/
FF_Error_t FF_GetEntry( FF_IOManager_t * pxIOManager,
uint16_t usEntry,
uint32_t ulDirCluster,
FF_DirEnt_t * pxDirent );
FF_Error_t FF_PutEntry( FF_IOManager_t * pxIOManager,
uint16_t usEntry,
uint32_t ulDirCluster,
FF_DirEnt_t * pxDirent,
uint8_t * pucContents );
int8_t FF_FindEntry( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster,
int8_t * Name,
FF_DirEnt_t * pxDirent,
BaseType_t LFNs );
void FF_PopulateShortDirent( FF_IOManager_t * pxIOManager,
FF_DirEnt_t * pxDirent,
const uint8_t * pucEntryBuffer );
FF_Error_t FF_PopulateLongDirent( FF_IOManager_t * pxIOManager,
FF_DirEnt_t * pxDirent,
uint16_t usEntry,
FF_FetchContext_t * pFetchContext );
FF_Error_t FF_InitEntryFetch( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster,
FF_FetchContext_t * pContext );
FF_Error_t FF_FetchEntryWithContext( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
FF_FetchContext_t * pContext,
uint8_t * pEntryBuffer );
FF_Error_t FF_PushEntryWithContext( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
FF_FetchContext_t * pContext,
uint8_t * pEntryBuffer );
FF_Error_t FF_CleanupEntryFetch( FF_IOManager_t * pxIOManager,
FF_FetchContext_t * pContext );
int8_t FF_PushEntry( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster,
uint16_t usEntry,
uint8_t * buffer,
void * pParam );
static portINLINE BaseType_t FF_isEndOfDir( const uint8_t * pucEntryBuffer )
{
return pucEntryBuffer[ 0 ] == ( uint8_t ) 0;
}
static portINLINE BaseType_t FF_isDeleted( const uint8_t * pucEntryBuffer )
{
return pucEntryBuffer[ 0 ] == ( uint8_t ) FF_FAT_DELETED;
}
struct _FF_FIND_PARAMS
{
uint32_t ulDirCluster; /* The beginning cluster of this directory. */
int32_t lFreeEntry; /* The first free entry big enough to add the file. */
uint32_t ulFlags; /* See FIND_FLAG_xxx defines above. */
char pcEntryBuffer[ 32 ]; /* LFN converted to short name. */
uint8_t ucCaseAttrib;
uint8_t ucFirstTilde;
};
typedef struct _FF_FIND_PARAMS FF_FindParams_t;
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
uint32_t FF_CreateFile( FF_IOManager_t * pxIOManager,
FF_FindParams_t * findParams,
FF_T_WCHAR * FileName,
FF_DirEnt_t * pxDirent,
FF_Error_t * pError );
uint32_t FF_FindEntryInDir( FF_IOManager_t * pxIOManager,
FF_FindParams_t * findParams,
const FF_T_WCHAR * name,
uint8_t pa_Attrib,
FF_DirEnt_t * pxDirent,
FF_Error_t * pError );
uint32_t FF_FindDir( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * pcPath,
uint16_t pathLen,
FF_Error_t * pError );
void FF_CreateShortName( FF_FindParams_t * pxFindParams,
const FF_T_WCHAR * pcLongName );
#else /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
uint32_t FF_CreateFile( FF_IOManager_t * pxIOManager,
FF_FindParams_t * findParams,
char * FileName,
FF_DirEnt_t * pxDirent,
FF_Error_t * pError );
uint32_t FF_FindEntryInDir( FF_IOManager_t * pxIOManager,
FF_FindParams_t * findParams,
const char * name,
uint8_t pa_Attrib,
FF_DirEnt_t * pxDirent,
FF_Error_t * pError );
uint32_t FF_FindDir( FF_IOManager_t * pxIOManager,
const char * pcPath,
uint16_t pathLen,
FF_Error_t * pError );
void FF_CreateShortName( FF_FindParams_t * pxFindParams,
const char * pcLongName );
#endif /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
int32_t FF_FindShortName( FF_IOManager_t * pxIOManager,
FF_FindParams_t * findParams );
FF_Error_t FF_CreateDirent( FF_IOManager_t * pxIOManager,
FF_FindParams_t * findParams,
FF_DirEnt_t * pxDirent );
FF_Error_t FF_ExtendDirectory( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster );
FF_Error_t FF_RmLFNs( FF_IOManager_t * pxIOManager,
uint16_t usDirEntry,
FF_FetchContext_t * pContext );
#if ( ffconfigHASH_CACHE != 0 )
BaseType_t FF_CheckDirentHash( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster,
uint32_t ulHash );
BaseType_t FF_DirHashed( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster );
void FF_AddDirentHash( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster,
uint32_t ulHash );
FF_Error_t FF_HashDir( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster );
void FF_UnHashDir( FF_IOManager_t * pxIOManager,
uint32_t ulDirCluster );
#endif /* if ( ffconfigHASH_CACHE != 0 ) */
struct SBuffStats
{
unsigned sectorMatch;
unsigned sectorMiss;
unsigned bufCounts;
unsigned bufCalls;
};
extern struct SBuffStats buffStats;
#endif /* ifndef _FF_DIR_H_ */

View File

@ -0,0 +1,264 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef _FF_ERROR_H_
#define _FF_ERROR_H_
/**
* @file ff_error.h
* @ingroup ERROR
**/
/**
* Error codes are 32-bit numbers, and consist of three items:
* 1Bit 7Bits 8Bits 16Bits
* . ........ ........ ........ ........
* [ErrFlag][ModuleID][FunctionID][-- ERROR CODE --]
*
* Error Codes should always have the ErrFlag set, this is the reason why all module
* codes include it.
*
* When returning an error simply return the defined Error Code, OR'd with the function
* name (capitalised) in which the error has occurred.
*
* When receiving an Error code from another layer, do not modify the code, as this will
* prevent the error code from containing the origin of the error, simply pass it to the
* next layer.
*
* Some API's have been defined to provide, useful and meaningful Error messages to the
* the 'userspace' application layer.
*
**/
#define FF_MODULE_SHIFT 24
#define FF_FUNCTION_SHIFT 16
#define FF_GETERROR( x ) ( ( ( unsigned ) x ) & 0xFFFF )
#define FF_GETMODULE( x ) ( ( ( ( unsigned ) x ) >> FF_MODULE_SHIFT ) & 0x7F )
#define FF_GETFUNCTION( x ) ( ( ( ( unsigned ) x ) >> FF_FUNCTION_SHIFT ) & 0xFF )
#define FF_GETMOD_FUNC( x ) ( ( ( ( unsigned ) x ) >> FF_FUNCTION_SHIFT ) & 0xFFFF )
#define FF_ERRFLAG 0x80000000
#define FF_isERR( x ) ( ( ( x ) & FF_ERRFLAG ) != 0 )
/*----- FreeRTOS+FAT Module Identifiers */
#define FF_MODULE_IOMAN ( ( 1 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_DIR ( ( 2 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_FILE ( ( 3 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_FAT ( ( 4 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_CRC ( ( 5 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_FORMAT ( ( 6 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_MEMORY ( ( 7 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_STRING ( ( 8 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_LOCKING ( ( 9 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_TIME ( ( 10 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_DRIVER ( ( 11 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
#define FF_MODULE_STDIO ( ( 12 << FF_MODULE_SHIFT ) | FF_ERRFLAG )
/*----- FreeRTOS+FAT Function Identifiers (In Modular Order) */
/*----- FF_IOManager_t - The FreeRTOS+FAT I/O Manager. */
#define FF_CREATEIOMAN ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_DESTROYIOMAN ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_MOUNT ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_UNMOUNT ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_FLUSHCACHE ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_GETPARTITIONBLOCKSIZE ( ( 6 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_BLOCKREAD ( ( 7 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_BLOCKWRITE ( ( 8 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_DETERMINEFATTYPE ( ( 9 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_GETEFIPARTITIONENTRY ( ( 10 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_USERDRIVER ( ( 11 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_DECREASEFREECLUSTERS ( ( 12 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_INCREASEFREECLUSTERS ( ( 13 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_PARTITIONSEARCH ( ( 14 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
#define FF_PARSEEXTENDED ( ( 15 << FF_FUNCTION_SHIFT ) | FF_MODULE_IOMAN )
/*----- FreeRTOS+FAT Return codes for user Rd/Wr routines */
#define FF_ERR_DRIVER_NOMEDIUM ( FF_ERR_IOMAN_DRIVER_NOMEDIUM | FF_USERDRIVER | FF_MODULE_DRIVER )
#define FF_ERR_DRIVER_BUSY ( FF_ERR_IOMAN_DRIVER_BUSY | FF_USERDRIVER | FF_MODULE_DRIVER )
#define FF_ERR_DRIVER_FATAL_ERROR ( FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_USERDRIVER | FF_MODULE_DRIVER )
/*----- FF_DIR - The FreeRTOS+FAT directory handling routines. */
#define FF_FETCHENTRYWITHCONTEXT ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_PUSHENTRYWITHCONTEXT ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_GETENTRY ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_FINDFIRST ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_FINDNEXT ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_REWINDFIND ( ( 6 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_FINDFREEDIRENT ( ( 7 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_PUTENTRY ( ( 8 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_CREATESHORTNAME ( ( 9 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_CREATELFNS ( ( 10 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_EXTENDDIRECTORY ( ( 11 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_MKDIR ( ( 12 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_TRAVERSE ( ( 13 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
#define FF_FINDDIR ( ( 14 << FF_FUNCTION_SHIFT ) | FF_MODULE_DIR )
/*----- FF_FILE - The FreeRTOS+FAT file handling routines. */
#define FF_GETMODEBITS ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_OPEN ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_ISDIREMPTY ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_RMDIR ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_RMFILE ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_MOVE ( ( 6 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_ISEOF ( ( 7 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_GETSEQUENTIALCLUSTERS ( ( 8 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_READCLUSTERS ( ( 9 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_EXTENDFILE ( ( 10 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_WRITECLUSTERS ( ( 11 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_READ ( ( 12 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_GETC ( ( 13 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_GETLINE ( ( 14 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_TELL ( ( 15 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_WRITE ( ( 16 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_PUTC ( ( 17 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_SEEK ( ( 18 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_INVALIDATE ( ( 19 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_CHECKVALID ( ( 20 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_CLOSE ( ( 21 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_SETTIME ( ( 22 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_BYTESLEFT ( ( 23 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_SETFILETIME ( ( 24 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_INITBUF ( ( 25 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
#define FF_SETEOF ( ( 26 << FF_FUNCTION_SHIFT ) | FF_MODULE_FILE )
/*----- FF_FAT - The FreeRTOS+FAT FAT handling routines. */
#define FF_GETFATENTRY ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT )
#define FF_CLEARCLUSTER ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT )
#define FF_PUTFATENTRY ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT )
#define FF_FINDFREECLUSTER ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT )
#define FF_COUNTFREECLUSTERS ( ( 5 << FF_FUNCTION_SHIFT ) | FF_MODULE_FAT )
/*----- FF_FORMAT - The FreeRTOS+FAT format routine */
#define FF_FORMATPARTITION ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_FORMAT )
/*----- FF_UNICODE - The FreeRTOS+FAT unicode routines. */
#define FF_UTF8CTOUTF16C ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING )
#define FF_UTF16CTOUTF8C ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING )
#define FF_UTF32CTOUTF16C ( ( 3 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING )
#define FF_UTF16CTOUTF32C ( ( 4 << FF_FUNCTION_SHIFT ) | FF_MODULE_STRING )
/*----- FF_STDIO - The stdio-interface to FreeRTOS+FAT. */
#define FF_CHMOD ( ( 1 << FF_FUNCTION_SHIFT ) | FF_MODULE_STDIO )
#define FF_STAT_FUNC ( ( 2 << FF_FUNCTION_SHIFT ) | FF_MODULE_STDIO )
/* FreeRTOS+FAT defines different Error-Code spaces for each module. This ensures
* that all error codes remain unique, and their meaning can be quickly identified.
*/
/* Global Error Codes */
#define FF_ERR_NONE 0 /* No Error */
/*#define FF_ERR_GENERIC 1*/ /* BAD NEVER USE THIS! -- Therefore commented out. */
#define FF_ERR_NULL_POINTER 2 /* Parameter was NULL. */
#define FF_ERR_NOT_ENOUGH_MEMORY 3 /* malloc() failed! - Could not allocate handle memory. */
#define FF_ERR_DEVICE_DRIVER_FAILED 4 /* The Block Device driver reported a FATAL error, cannot continue. */
/* User return codes for Rd/Wr functions: */
#define FF_ERR_IOMAN_DRIVER_NOMEDIUM 8
#define FF_ERR_IOMAN_DRIVER_BUSY 9
#define FF_ERR_IOMAN_DRIVER_FATAL_ERROR 10
/* IOMAN Error Codes */
#define FF_ERR_IOMAN_BAD_BLKSIZE 11 /* The provided blocksize was not a multiple of 512. */
#define FF_ERR_IOMAN_BAD_MEMSIZE 12 /* The memory size was not a multiple of the blocksize. */
#define FF_ERR_IOMAN_DEV_ALREADY_REGD 13 /* Device was already registered. Use FF_UnRegister() to re-use this IOMAN with another device. */
#define FF_ERR_IOMAN_NO_MOUNTABLE_PARTITION 14 /* A mountable partition could not be found on the device. */
#define FF_ERR_IOMAN_INVALID_FORMAT 15
#define FF_ERR_IOMAN_INVALID_PARTITION_NUM 16 /* The partition number provided was out of range. */
#define FF_ERR_IOMAN_NOT_FAT_FORMATTED 17 /* The partition did not look like a FAT partition. */
#define FF_ERR_IOMAN_DEV_INVALID_BLKSIZE 18 /* IOMAN object BlkSize is not compatible with the blocksize of this device driver. */
#define FF_ERR_IOMAN_PARTITION_MOUNTED 19 /* Device is in use by an actively mounted partition. Unmount the partition first. */
#define FF_ERR_IOMAN_ACTIVE_HANDLES 20 /* The partition cannot be unmounted until all active file handles are closed. (There may also be active handles on the cache). */
#define FF_ERR_IOMAN_GPT_HEADER_CORRUPT 21 /* The GPT partition table appears to be corrupt, refusing to mount. */
#define FF_ERR_IOMAN_NOT_ENOUGH_FREE_SPACE 22
#define FF_ERR_IOMAN_OUT_OF_BOUNDS_READ 23
#define FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE 24
/* File Error Codes 30 + */
#define FF_ERR_FILE_ALREADY_OPEN 30 /* File is in use. */
#define FF_ERR_FILE_NOT_FOUND 31 /* File was not found. */
#define FF_ERR_FILE_OBJECT_IS_A_DIR 32 /* Tried to FF_Open() a Directory. */
#define FF_ERR_FILE_IS_READ_ONLY 33 /* Tried to FF_Open() a file marked read only. */
#define FF_ERR_FILE_INVALID_PATH 34 /* The path of the file was not found. */
#define FF_ERR_FILE_NOT_OPENED_IN_WRITE_MODE 35
#define FF_ERR_FILE_NOT_OPENED_IN_READ_MODE 36
#define FF_ERR_FILE_EXTEND_FAILED 37 /* Could not extend the file. */
#define FF_ERR_FILE_DESTINATION_EXISTS 38
#define FF_ERR_FILE_SOURCE_NOT_FOUND 39
#define FF_ERR_FILE_DIR_NOT_FOUND 40
#define FF_ERR_FILE_COULD_NOT_CREATE_DIRENT 41
#define FF_ERR_FILE_BAD_HANDLE 42 /* A file handle was invalid */
#define FF_ERR_FILE_MEDIA_REMOVED 43 /* File handle got invalid because media was removed */
#define FF_ERR_FILE_READ_ZERO 44 /* Used internally. */
#define FF_ERR_FILE_SEEK_INVALID_ORIGIN 45 /* Seeking beyond end of file. */
#define FF_ERR_FILE_SEEK_INVALID_POSITION 46 /* Bad value for the 'whence' parameter. */
/* Directory Error Codes 50 + */
#define FF_ERR_DIR_OBJECT_EXISTS 50 /* A file or folder of the same name already exists in the current directory. */
#define FF_ERR_DIR_DIRECTORY_FULL 51 /* No more items could be added to the directory. */
#define FF_ERR_DIR_END_OF_DIR 52 /*/ */
#define FF_ERR_DIR_NOT_EMPTY 53 /* Cannot delete a directory that contains files or folders. */
#define FF_ERR_DIR_INVALID_PATH 54 /* Could not find the directory specified by the path. */
#define FF_ERR_DIR_INVALID_PARAMETER 55 /* Could not find the directory specified by the path. */
#define FF_ERR_DIR_CANT_EXTEND_ROOT_DIR 56 /* Can't extend the root dir. */
#define FF_ERR_DIR_EXTEND_FAILED 57 /* Not enough space to extend the directory. */
#define FF_ERR_DIR_NAME_TOO_LONG 58 /* Name exceeds the number of allowed characters for a filename. */
/* Fat Error Codes 70 + */
#define FF_ERR_FAT_NO_FREE_CLUSTERS 70 /* No more free space is available on the disk. */
/* UNICODE Error Codes 100 + */
#define FF_ERR_UNICODE_INVALID_CODE 100 /* An invalid Unicode character was provided! */
#define FF_ERR_UNICODE_DEST_TOO_SMALL 101 /* Not enough space in the UTF-16 buffer to encode the entire sequence as UTF-16. */
#define FF_ERR_UNICODE_INVALID_SEQUENCE 102 /* An invalid UTF-16 sequence was encountered. */
#define FF_ERR_UNICODE_CONVERSION_EXCEEDED 103 /* Filename exceeds MAX long-filename length when converted to UTF-16. */
typedef int32_t FF_Error_t;
#if ( ffconfigDEBUG != 0 )
const char * FF_GetErrMessage( FF_Error_t iErrorCode );
const char * FF_GetErrModule( FF_Error_t iErrorCode );
const char * FF_GetErrFunction( FF_Error_t iErrorCode );
const char * FF_GetErrDescription( FF_Error_t iErrorCode,
char * pcBuffer,
int iMaxLength ); /* Get the complete description */
#else /* ffconfigDEBUG */
#define FF_GetErrMessage( X ) "" /* A special MACRO in case FF_GetErrMessage() isn't gated with ffconfigDEBUG */
#define FF_GetErrModule( X ) ""
#define FF_GetErrFunction( X ) ""
static portINLINE const char * FF_GetErrDescription( FF_Error_t iErrorCode,
char * pcBuffer,
int iMaxLength )
{
( void ) iErrorCode;
( void ) iMaxLength;
strcpy( pcBuffer, "unknown" );
return pcBuffer;
}
#endif /* Function call is safely replaced with a NULL string. */
#endif /* INCLUDE GUARD END */

View File

@ -0,0 +1,168 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_fat.h
* @ingroup FAT
**/
#ifndef _FF_FAT_H_
#define _FF_FAT_H_
#ifndef PLUS_FAT_H
#error this header will be included from "ff_headers.h"
#endif
/*---------- ERROR CODES */
/*---------- PROTOTYPES */
/* HT statistics Will be taken away after testing: */
#if ( ffconfigFAT_USES_STAT != 0 )
struct SFatStat
{
unsigned initCount;
unsigned clearCount;
unsigned getCount[ 2 ]; /* Index 0 for READ counts, index 1 for WRITE counts. */
unsigned reuseCount[ 2 ];
unsigned missCount[ 2 ];
};
extern struct SFatStat fatStat;
#endif /* if ( ffconfigFAT_USES_STAT != 0 ) */
#if ( ffconfigWRITE_BOTH_FATS != 0 )
#define ffconfigBUF_STORE_COUNT 2
#else
#define ffconfigBUF_STORE_COUNT 1
#endif
typedef struct _FatBuffers
{
FF_Buffer_t * pxBuffers[ ffconfigBUF_STORE_COUNT ];
uint8_t ucMode; /* FF_MODE_READ or WRITE. */
} FF_FATBuffers_t;
uint32_t FF_getClusterPosition( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
uint32_t ulEntrySize );
uint32_t FF_getClusterChainNumber( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
uint32_t ulEntrySize );
uint32_t FF_getMajorBlockNumber( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
uint32_t ulEntrySize );
uint32_t FF_getMinorBlockNumber( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
uint32_t ulEntrySize );
uint32_t FF_getMinorBlockEntry( FF_IOManager_t * pxIOManager,
uint32_t ulEntry,
uint32_t ulEntrySize );
/* A partition may define a block size larger than 512 bytes (at offset 0x0B of the PBR).
* This function translates a block address to an address based on 'pxIOManager->usBlkSize',
* which is usually 512 bytes.
*/
static portINLINE uint32_t FF_getRealLBA( FF_IOManager_t * pxIOManager,
uint32_t LBA )
{
return LBA * pxIOManager->xPartition.ucBlkFactor;
}
uint32_t FF_Cluster2LBA( FF_IOManager_t * pxIOManager,
uint32_t ulCluster );
uint32_t FF_LBA2Cluster( FF_IOManager_t * pxIOManager,
uint32_t ulAddress );
uint32_t FF_getFATEntry( FF_IOManager_t * pxIOManager,
uint32_t ulCluster,
FF_Error_t * pxError,
FF_FATBuffers_t * pxFATBuffers );
FF_Error_t FF_putFATEntry( FF_IOManager_t * pxIOManager,
uint32_t ulCluster,
uint32_t ulValue,
FF_FATBuffers_t * pxFATBuffers );
BaseType_t FF_isEndOfChain( FF_IOManager_t * pxIOManager,
uint32_t ulFatEntry );
uint32_t FF_FindFreeCluster( FF_IOManager_t * pxIOManager,
FF_Error_t * pxError,
BaseType_t aDoClaim );
uint32_t FF_ExtendClusterChain( FF_IOManager_t * pxIOManager,
uint32_t ulStartCluster,
uint32_t ulCount );
FF_Error_t FF_UnlinkClusterChain( FF_IOManager_t * pxIOManager,
uint32_t ulStartCluster,
BaseType_t xDoTruncate );
uint32_t FF_TraverseFAT( FF_IOManager_t * pxIOManager,
uint32_t ulStart,
uint32_t ulCount,
FF_Error_t * pxError );
uint32_t FF_CreateClusterChain( FF_IOManager_t * pxIOManager,
FF_Error_t * pxError );
uint32_t FF_GetChainLength( FF_IOManager_t * pxIOManager,
uint32_t pa_nStartCluster,
uint32_t * piEndOfChain,
FF_Error_t * pxError );
uint32_t FF_FindEndOfChain( FF_IOManager_t * pxIOManager,
uint32_t Start,
FF_Error_t * pxError );
FF_Error_t FF_ClearCluster( FF_IOManager_t * pxIOManager,
uint32_t ulCluster );
#if ( ffconfig64_NUM_SUPPORT != 0 )
uint64_t FF_GetFreeSize( FF_IOManager_t * pxIOManager,
FF_Error_t * pxError );
#else
uint32_t FF_GetFreeSize( FF_IOManager_t * pxIOManager,
FF_Error_t * pxError );
#endif
/* WARNING: If this prototype changes, it must be updated in ff_ioman.c also! */
uint32_t FF_CountFreeClusters( FF_IOManager_t * pxIOManager,
FF_Error_t * pxError );
FF_Error_t FF_ReleaseFATBuffers( FF_IOManager_t * pxIOManager,
FF_FATBuffers_t * pxFATBuffers );
static portINLINE void FF_InitFATBuffers( FF_FATBuffers_t * pxFATBuffers,
uint8_t ucMode )
{
pxFATBuffers->pxBuffers[ 0 ] = NULL;
#if ffconfigBUF_STORE_COUNT > 1
pxFATBuffers->pxBuffers[ 1 ] = NULL;
#endif
#if ffconfigBUF_STORE_COUNT > 2
#error Please check this code, maybe it is time to use memset
#endif
pxFATBuffers->ucMode = ucMode; /* FF_MODE_READ/WRITE */
#if ffconfigFAT_USES_STAT
{
fatStat.initCount++;
}
#endif
}
#endif /* ifndef _FF_FAT_H_ */

View File

@ -0,0 +1,108 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef _FF_FATDEF_H_
#define _FF_FATDEF_H_
/*
* This file defines offsets to various data for the FAT specification.
*/
/* MBR / PBR Offsets. */
#define FF_FAT_BYTES_PER_SECTOR 0x00B
#define FF_FAT_SECTORS_PER_CLUS 0x00D
#define FF_FAT_RESERVED_SECTORS 0x00E
#define FF_FAT_NUMBER_OF_FATS 0x010
#define FF_FAT_ROOT_ENTRY_COUNT 0x011
#define FF_FAT_16_TOTAL_SECTORS 0x013
#define FF_FAT_MEDIA_TYPE 0x015
#define FF_FAT_32_TOTAL_SECTORS 0x020
#define FF_FAT_16_SECTORS_PER_FAT 0x016
#define FF_FAT_32_SECTORS_PER_FAT 0x024
#define FF_FAT_ROOT_DIR_CLUSTER 0x02C
#define FF_FAT_EXT_BOOT_SIGNATURE 0x042
#define FF_FAT_16_VOL_LABEL 0x02B
#define FF_FAT_32_VOL_LABEL 0x047
#define FF_FAT_PTBL 0x1BE
#define FF_FAT_PTBL_LBA 0x008
#define FF_FAT_PTBL_SECT_COUNT 0x00C
#define FF_FAT_PTBL_ACTIVE 0x000
#define FF_FAT_PTBL_ID 0x004
#define FF_DOS_EXT_PART 0x05
#define FF_LINUX_EXT_PART 0x85
#define FF_WIN98_EXT_PART 0x0f
#define FF_FAT_MBR_SIGNATURE 0x1FE
#define FF_FAT_DELETED 0xE5
/* Directory Entry Offsets. */
#define FF_FAT_DIRENT_SHORTNAME 0x000
#define FF_FAT_DIRENT_ATTRIB 0x00B
#define FF_FAT_DIRENT_CREATE_TIME 0x00E /* Creation Time. */
#define FF_FAT_DIRENT_CREATE_DATE 0x010 /* Creation Date. */
#define FF_FAT_DIRENT_LASTACC_DATE 0x012 /* Date of Last Access. */
#define FF_FAT_DIRENT_CLUS_HIGH 0x014
#define FF_FAT_DIRENT_LASTMOD_TIME 0x016 /* Time of Last modification. */
#define FF_FAT_DIRENT_LASTMOD_DATE 0x018 /* Date of Last modification. */
#define FF_FAT_DIRENT_CLUS_LOW 0x01A
#define FF_FAT_DIRENT_FILESIZE 0x01C
#define FF_FAT_LFN_ORD 0x000
#define FF_FAT_LFN_NAME_1 0x001
#define FF_FAT_LFN_CHECKSUM 0x00D
#define FF_FAT_LFN_NAME_2 0x00E
#define FF_FAT_LFN_NAME_3 0x01C
/* Dirent Attributes. */
#define FF_FAT_ATTR_READONLY 0x01
#define FF_FAT_ATTR_HIDDEN 0x02
#define FF_FAT_ATTR_SYSTEM 0x04
#define FF_FAT_ATTR_VOLID 0x08
#define FF_FAT_ATTR_DIR 0x10
#define FF_FAT_ATTR_ARCHIVE 0x20
#define FF_FAT_ATTR_LFN 0x0F
/**
* -- Hein_Tibosch additions for mixed case in shortnames --
*
* Specifically, bit 4 means lowercase extension and bit 3 lowercase basename,
* which allows for combinations such as "example.TXT" or "HELLO.txt" but not "Mixed.txt"
*/
#define FF_FAT_CASE_OFFS 0x0C /* After NT/XP : 2 case bits. */
#define FF_FAT_CASE_ATTR_BASE 0x08
#define FF_FAT_CASE_ATTR_EXT 0x10
#if ( ffconfigLFN_SUPPORT != 0 ) && ( ffconfigINCLUDE_SHORT_NAME != 0 )
#define FF_FAT_ATTR_IS_LFN 0x40 /* artificial attribute, for debugging only. */
#endif
#endif /* ifndef _FF_FATDEF_H_ */

View File

@ -0,0 +1,204 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_file.h
* @ingroup FILEIO
**/
#ifndef _FF_FILE_H_
#define _FF_FILE_H_
#ifndef PLUS_FAT_H
#error this header will be included from "ff_headers.h"
#endif
#define FF_SEEK_SET 0
#define FF_SEEK_CUR 1
#define FF_SEEK_END 2
#if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
#define FF_BUFSTATE_INVALID 0x00 /* Data in file handle buffer is invalid. */
#define FF_BUFSTATE_VALID 0x01 /* Valid data in pBuf (Something has been read into it). */
#define FF_BUFSTATE_WRITTEN 0x02 /* Data was written into pBuf, this must be saved when leaving sector. */
#endif
#if ( ffconfigDEV_SUPPORT != 0 )
struct xDEV_NODE
{
uint8_t
ucIsDevice;
};
#endif
typedef struct _FF_FILE
{
FF_IOManager_t * pxIOManager; /* Ioman Pointer! */
uint32_t ulFileSize; /* File's Size. */
uint32_t ulObjectCluster; /* File's Start Cluster. */
uint32_t ulChainLength; /* Total Length of the File's cluster chain. */
uint32_t ulCurrentCluster; /* Prevents FAT Thrashing. */
uint32_t ulAddrCurrentCluster; /* Address of the current cluster. */
uint32_t ulEndOfChain; /* Address of the last cluster in the chain. */
uint32_t ulFilePointer; /* Current Position Pointer. */
uint32_t ulDirCluster; /* Cluster Number that the Dirent is in. */
uint32_t ulValidFlags; /* Handle validation flags. */
#if ( ffconfigOPTIMISE_UNALIGNED_ACCESS != 0 )
uint8_t * pucBuffer; /* A buffer for providing fast unaligned access. */
uint8_t ucState; /* State information about the buffer. */
#endif
uint8_t ucMode; /* Mode that File Was opened in. */
uint16_t usDirEntry; /* Dirent Entry Number describing this file. */
#if ( ffconfigDEV_SUPPORT != 0 )
struct SFileCache * pxDevNode;
#endif
struct _FF_FILE * pxNext; /* Pointer to the next file object in the linked list. */
} FF_FILE;
#define FF_VALID_FLAG_INVALID 0x00000001
#define FF_VALID_FLAG_DELETED 0x00000002
/*---------- PROTOTYPES */
/* PUBLIC (Interfaces): */
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_FILE * FF_Open( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * path,
uint8_t Mode,
FF_Error_t * pError );
BaseType_t FF_isDirEmpty( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * Path );
FF_Error_t FF_RmFile( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * path );
FF_Error_t FF_RmDir( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * path );
FF_Error_t FF_Move( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * szSourceFile,
const FF_T_WCHAR * szDestinationFile,
BaseType_t bDeleteIfExists );
#else /* ffconfigUNICODE_UTF16_SUPPORT */
FF_FILE * FF_Open( FF_IOManager_t * pxIOManager,
const char * path,
uint8_t Mode,
FF_Error_t * pError );
BaseType_t FF_isDirEmpty( FF_IOManager_t * pxIOManager,
const char * Path );
FF_Error_t FF_RmFile( FF_IOManager_t * pxIOManager,
const char * path );
FF_Error_t FF_RmDir( FF_IOManager_t * pxIOManager,
const char * path );
FF_Error_t FF_Move( FF_IOManager_t * pxIOManager,
const char * szSourceFile,
const char * szDestinationFile,
BaseType_t bDeleteIfExists );
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
#if ( ffconfigTIME_SUPPORT != 0 )
enum
{
ETimeCreate = 1,
ETimeMod = 2,
ETimeAccess = 4,
ETimeAll = 7
};
FF_Error_t FF_SetFileTime( FF_FILE * pFile,
FF_SystemTime_t * pxTime,
UBaseType_t uxWhat );
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_Error_t FF_SetTime( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * path,
FF_SystemTime_t * pxTime,
UBaseType_t uxWhat );
#else
FF_Error_t FF_SetTime( FF_IOManager_t * pxIOManager,
const char * path,
FF_SystemTime_t * pxTime,
UBaseType_t uxWhat );
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
#endif /* ffconfigTIME_SUPPORT */
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager,
const FF_T_WCHAR * path,
UBaseType_t aPerm );
#else
FF_Error_t FF_SetPerm( FF_IOManager_t * pxIOManager,
const char * path,
UBaseType_t aPerm );
#endif
FF_Error_t FF_SetEof( FF_FILE * pFile );
FF_Error_t FF_Close( FF_FILE * pFile );
int32_t FF_GetC( FF_FILE * pFile );
int32_t FF_GetLine( FF_FILE * pFile,
char * szLine,
uint32_t ulLimit );
int32_t FF_Read( FF_FILE * pFile,
uint32_t ElementSize,
uint32_t Count,
uint8_t * buffer );
int32_t FF_Write( FF_FILE * pFile,
uint32_t ElementSize,
uint32_t Count,
uint8_t * buffer );
BaseType_t FF_isEOF( FF_FILE * pFile );
int32_t FF_BytesLeft( FF_FILE * pFile ); /* Returns # of bytes left to read. */
/* FF_FileSize is an earlier version of FF_GetFileSize(). For files
* equal to or larger than 2GB, the return value is negative.
* Function is deprecated. Please use FF_GetFileSize(). */
int32_t FF_FileSize( FF_FILE * pFile ); /* Returns # of bytes in a file. */
/* Use the following function in case files may get larger than 2 GB.
* Writes the size of a file to the parameter.
* Returns 0 or error code. */
FF_Error_t FF_GetFileSize( FF_FILE * pFile,
uint32_t * pulSize );
FF_Error_t FF_Seek( FF_FILE * pFile,
int32_t Offset,
BaseType_t xOrigin );
int32_t FF_PutC( FF_FILE * pFile,
uint8_t Value );
static portINLINE uint32_t FF_Tell( FF_FILE * pFile )
{
return pFile ? pFile->ulFilePointer : 0;
}
uint8_t FF_GetModeBits( const char * Mode );
FF_Error_t FF_CheckValid( FF_FILE * pFile ); /* Check if pFile is a valid FF_FILE pointer. */
#if ( ffconfigREMOVABLE_MEDIA != 0 )
int32_t FF_Invalidate( FF_IOManager_t * pxIOManager ); /* Invalidate all handles belonging to pxIOManager. */
#endif
/* Private : */
#endif /* ifndef _FF_FILE_H_ */

View File

@ -0,0 +1,87 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_format.c
* @ingroup FORMAT
*
**/
#ifndef _FF_FORMAT_H_
#define _FF_FORMAT_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef PLUS_FAT_H
#error this header will be included from "ff_headers.h"
#endif
/*---------- PROTOTYPES */
/* PUBLIC (Interfaces): */
typedef enum _FF_SizeType
{
eSizeIsQuota, /* Assign a quotum (sum of xSizes is free, all disk space will be allocated) */
eSizeIsPercent, /* Assign a percentage of the available space (sum of xSizes must be <= 100) */
eSizeIsSectors, /* Assign fixed number of sectors (sum of xSizes must be < ulSectorCount) */
} eSizeType_t;
typedef struct _FF_PartitionParameters
{
uint32_t ulSectorCount; /* Total number of sectors on the disk, including hidden/reserved */
/* Must be obtained from the block driver */
uint32_t ulHiddenSectors; /* Keep at least these initial sectors free */
uint32_t ulInterSpace; /* Number of sectors to keep free between partitions (when 0 -> 2048) */
BaseType_t xSizes[ ffconfigMAX_PARTITIONS ]; /* E.g. 80, 20, 0, 0 (see eSizeType) */
BaseType_t xPrimaryCount; /* The number of partitions that must be "primary" */
eSizeType_t eSizeType;
} FF_PartitionParameters_t;
FF_Error_t FF_Partition( FF_Disk_t * pxDisk,
FF_PartitionParameters_t * pParams );
FF_Error_t FF_Format( FF_Disk_t * pxDisk,
BaseType_t xPartitionNumber,
BaseType_t xPreferFAT16,
BaseType_t xSmallClusters );
FF_Error_t FF_FormatDisk( FF_Disk_t * pxDisk,
BaseType_t xPartitionNumber,
BaseType_t xPreferFAT16,
BaseType_t xSmallClusters,
const char * pcVolumeName );
/* Private : */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ifndef _FF_FORMAT_H_ */

View File

@ -0,0 +1,62 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef PLUS_FAT_H
#define PLUS_FAT_H
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "FreeRTOSFATConfig.h"
#include "FreeRTOSFATConfigDefaults.h"
#include "ff_error.h"
#include "ff_string.h"
#include "ff_ioman.h"
#include "ff_fat.h"
#include "ff_fatdef.h"
#include "ff_memory.h"
#include "ff_time.h"
#include "ff_crc.h"
#include "ff_file.h"
#include "ff_dir.h"
#include "ff_format.h"
#include "ff_locking.h"
/* See if any older defines with a prefix "FF_" are still defined: */
#include "ff_old_config_defines.h"
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ifndef PLUS_FAT_H */

View File

@ -0,0 +1,414 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_ioman.h
* @ingroup IOMAN
**/
#ifndef _FF_IOMAN_H_
#define _FF_IOMAN_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h> /* Use of malloc() */
#ifndef PLUS_FAT_H
#error this header will be included from "ff_headers.h"
#endif
#define FF_T_FAT12 0x0A
#define FF_T_FAT16 0x0B
#define FF_T_FAT32 0x0C
#define FF_MODE_READ 0x01 /* Buffer / FILE Mode for Read Access. */
#define FF_MODE_WRITE 0x02 /* Buffer / FILE Mode for Write Access. */
#define FF_MODE_APPEND 0x04 /* FILE Mode Append Access. */
#define FF_MODE_CREATE 0x08 /* FILE Mode Create file if not existing. */
#define FF_MODE_TRUNCATE 0x10 /* FILE Mode Truncate an Existing file. */
#define FF_MODE_VIRGIN 0x40 /* Buffer mode: do not fetch content from disk. Used for write-only buffers. */
#define FF_MODE_DIR 0x80 /* Special Mode to open a Dir. (Internal use ONLY!) */
#define FF_MODE_RD_WR ( FF_MODE_READ | FF_MODE_WRITE ) /* Just for bit filtering. */
/* The buffer write-only mode saves a fetch from disk.
* The write-only mode is used when a buffer is needed just
* for clearing sectors. */
#define FF_MODE_WR_ONLY ( FF_MODE_VIRGIN | FF_MODE_WRITE ) /* Buffer for Write-only Access (Internal use ONLY!) */
#define FF_BUF_MAX_HANDLES 0xFFFF /* Maximum number handles sharing a buffer. (16 bit integer, we don't want to overflow it!) */
#define FF_MAX_ENTRIES_PER_DIRECTORY 0xFFFF
#define FF_SIZEOF_DIRECTORY_ENTRY 32
#ifndef pdTRUE_SIGNED
/* Temporary solution: eventually the defines below will appear
* in 'Source\include\projdefs.h' */
#define pdTRUE_SIGNED pdTRUE
#define pdFALSE_SIGNED pdFALSE
#define pdTRUE_UNSIGNED ( ( UBaseType_t ) 1u )
#define pdFALSE_UNSIGNED ( ( UBaseType_t ) 0u )
#endif
/**
* I/O Driver Definitions
* Provide access to any Block Device via the following interfaces.
* Returns the number of blocks actually read or written.
**/
/**
* A special information structure for the FreeRTOS+FAT mass storage device
* driver model.
**/
typedef struct
{
uint16_t BlkSize;
uint32_t TotalBlocks;
} FF_DeviceInfo_t;
#if ( ffconfigHASH_CACHE != 0 )
#define FF_HASH_TABLE_ENTRY_COUNT ( ( ffconfigHASH_TABLE_SIZE + 3 ) / 4 )
struct xHASH_TABLE
{
uint32_t ulDirCluster; /* The Starting Cluster of the dir that the hash represents. */
uint32_t ulNumHandles; /* Number of active Handles using this hash table. */
uint32_t ulMisses; /* Number of times this Hash Table was missed, (i.e. how redundant it is). */
uint32_t ulBitTable[ FF_HASH_TABLE_ENTRY_COUNT ];
};
typedef struct xHASH_TABLE FF_HashTable_t;
void FF_ClearHash( FF_HashTable_t * pxHash,
uint32_t ulHash );
void FF_SetHash( FF_HashTable_t * pxHash,
uint32_t ulHash );
BaseType_t FF_isHashSet( FF_HashTable_t * pxHash,
uint32_t ulHash );
#endif /* ffconfigHASH_CACHE */
/* A forward declaration for the I/O manager, to be used in 'struct xFFDisk'. */
struct _FF_IOMAN;
struct xFFDisk;
typedef void ( * FF_FlushApplicationHook )( struct xFFDisk * pxDisk );
/*
* Some low-level drivers also need to flush data to a device.
* Use an Application hook that will be called every time when
* FF_FlushCache() is called. The semaphore will still be taken
* to avoid unwanted reentrancy.
* For example:
*
* void FTL_FlushData( struct xFFDisk *pxDisk )
* {
* // You may or may not inspect 'pxDisk'
* FTL_FlushTableCache();
* }
*
* Make sure you bind the function to the disc object, right after creation:
*
* pxDisk->fnFlushApplicationHook = FTL_FlushData;
*/
/* Structure that contains fields common to all media drivers, and can be
* extended to contain additional fields to tailor it for use with a specific media
* type. */
struct xFFDisk
{
struct
{
/* Flags that can optionally be used by the media driver to ensure the
* disk has been initialised, registered and mounted before it is accessed. */
uint32_t bIsInitialised : 1;
uint32_t bIsMounted : 1;
uint32_t spare0 : 5;
/* The partition number on the media described by this structure. */
uint32_t bPartitionNumber : 8;
uint32_t spare1 : 16;
}
xStatus;
/* Provided to allow this structure to be extended to include additional
* attributes that are specific to a media type. */
void * pvTag;
/* Points to input and output manager used by the disk described by this
* structure. */
struct _FF_IOMAN * pxIOManager;
/* The number of sectors on the disk. */
uint32_t ulNumberOfSectors;
/* See comments here above. */
FF_FlushApplicationHook fnFlushApplicationHook;
/* Field that can optionally be set to a signature that is unique to the
* media. Read and write functions can check the ulSignature field to validate
* the media type before they attempt to access the pvTag field, or perform any
* read and write operations. */
uint32_t ulSignature;
};
typedef struct xFFDisk FF_Disk_t;
typedef int32_t ( * FF_WriteBlocks_t ) ( uint8_t * pucBuffer,
uint32_t ulSectorAddress,
uint32_t ulCount,
FF_Disk_t * pxDisk );
typedef int32_t ( * FF_ReadBlocks_t ) ( uint8_t * pucBuffer,
uint32_t ulSectorAddress,
uint32_t ulCount,
FF_Disk_t * pxDisk );
/**
* @public
* @brief Describes the block device driver interface to FreeRTOS+FAT.
**/
typedef struct
{
FF_WriteBlocks_t fnpWriteBlocks; /* Function Pointer, to write a block(s) from a block device. */
FF_ReadBlocks_t fnpReadBlocks; /* Function Pointer, to read a block(s) from a block device. */
FF_Disk_t * pxDisk; /* Earlier called 'pParam': pointer to some parameters e.g. for a Low-Level Driver Handle. */
} FF_BlockDevice_t;
/**
* @private
* @brief FreeRTOS+FAT handles memory with buffers, described as below.
* @note This may change throughout development.
**/
typedef struct
{
uint32_t ulSector; /* The LBA of the Cached sector. */
uint32_t ulLRU; /* For the Least Recently Used algorithm. */
uint8_t * pucBuffer; /* Pointer to the cache block. */
uint32_t ucMode : 8, /* Read or Write mode. */
bModified : 1, /* If the sector was modified since read. */
bValid : 1; /* Initially FALSE. */
uint16_t usNumHandles; /* Number of objects using this buffer. */
uint16_t usPersistance; /* For the persistance algorithm. */
} FF_Buffer_t;
typedef struct
{
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
FF_T_WCHAR pcPath[ ffconfigMAX_FILENAME ];
#else
char pcPath[ ffconfigMAX_FILENAME ];
#endif
uint32_t ulDirCluster;
} FF_PathCache_t;
/**
* @private
* @brief FreeRTOS+FAT identifies a partition with the following data.
* @note This may shrink as development and optimisation goes on.
**/
typedef struct
{
uint32_t ulBeginLBA; /* LBA start address of the partition. */
uint32_t ulFATBeginLBA; /* LBA of the FAT tables. */
uint32_t ulSectorsPerFAT; /* Number of sectors per Fat. */
uint32_t ulTotalSectors;
uint32_t ulDataSectors;
#if ( ffconfigWRITE_FREE_COUNT != 0 )
uint32_t ulFSInfoLBA; /* LBA of the FSINFO sector. */
#endif
uint32_t ulRootDirSectors;
uint32_t ulFirstDataSector;
uint32_t ulClusterBeginLBA; /* LBA of first cluster. */
uint32_t ulNumClusters; /* Number of clusters. */
uint32_t ulRootDirCluster; /* Cluster number of the root directory entry. */
uint32_t ulLastFreeCluster;
uint32_t ulFreeClusterCount; /* Records free space on mount. */
uint32_t ulSectorsPerCluster; /* Number of sectors per Cluster. */
char pcVolumeLabel[ 12 ]; /* Volume Label of the partition. */
uint16_t usBlkSize; /* Size of a Sector Block in bytes. */
uint16_t usReservedSectors;
uint8_t ucType; /* Partition Type Identifier. */
uint8_t ucBlkFactor; /* Scale Factor for block sizes above 512! */
uint8_t ucNumFATS; /* Number of FAT tables. */
uint8_t ucPartitionMounted; /* pdTRUE if the partition is mounted, otherwise pdFALSE. */
#if ( ffconfigPATH_CACHE != 0 )
FF_PathCache_t pxPathCache[ ffconfigPATH_CACHE_DEPTH ];
uint32_t ulPCIndex;
#endif
} FF_Partition_t;
/**
* @public
* @brief FF_IOManager_t Object description.
*
* FreeRTOS+FAT functions around an object like this.
**/
#define FF_FAT_LOCK 0x01 /* Lock bit mask for FAT table locking. */
#define FF_DIR_LOCK 0x02 /* Lock bit mask for DIR modification locking. */
#define FF_BUF_LOCK 0x04 /* Lock bit mask for buffers. */
/**
* @public
* @brief FF_IOManager_t Object. A developer should not touch these values.
*
**/
typedef struct _FF_IOMAN
{
FF_BlockDevice_t xBlkDevice; /* Pointer to a Block device description. */
FF_Partition_t xPartition; /* A partition description. */
FF_Buffer_t * pxBuffers; /* Pointer to an array of buffer descriptors. */
void * pvSemaphore; /* Pointer to a Semaphore object. (For buffer description modifications only!). */
void * FirstFile; /* Pointer to the first File object. */
void * xEventGroup; /* An event group, used for locking FAT, DIR and Buffers. Replaces ucLocks. */
uint8_t * pucCacheMem; /* Pointer to a block of memory for the cache. */
uint16_t usSectorSize; /* The sector size that IOMAN is configured to. */
uint16_t usCacheSize; /* Size of the cache in number of Sectors. */
uint8_t ucPreventFlush; /* Flushing to disk only allowed when 0. */
uint8_t ucFlags; /* Bit-Mask: identifying allocated pointers and other flags */
#if ( ffconfigHASH_CACHE != 0 )
FF_HashTable_t xHashCache[ ffconfigHASH_CACHE_DEPTH ];
#endif
void * pvFATLockHandle;
} FF_IOManager_t;
/* Bit values for 'FF_IOManager_t::ucFlags': */
/* Memory Allocation testing and other flags. */
#define FF_IOMAN_ALLOC_BUFDESCR 0x01 /* Flags the pxBuffers pointer is allocated. */
#define FF_IOMAN_ALLOC_BUFFERS 0x02 /* Flags the pucCacheMem pointer is allocated. */
#define FF_IOMAN_BLOCK_DEVICE_IS_REENTRANT 0x10 /* When true, ffRead/ffWrite are not protected by a semaphore. */
#if ( ffconfigREMOVABLE_MEDIA != 0 )
#define FF_IOMAN_DEVICE_IS_EXTRACTED 0x20
#endif /* ffconfigREMOVABLE_MEDIA */
typedef struct xFF_CREATION_PARAMETERS
{
uint8_t * pucCacheMemory; /* User provided memory, or use NULL to malloc the cache memory. */
uint32_t ulMemorySize; /* Size of the cache memory, must be a multiple of 'ulSectorSize'. */
BaseType_t ulSectorSize; /* Sector size, unit for reading/writing to the disk, normally 512 bytes. */
FF_WriteBlocks_t fnWriteBlocks; /* A function to write sectors to the device. */
FF_ReadBlocks_t fnReadBlocks; /* A function to read sectors from the device. */
FF_Disk_t * pxDisk; /* Some properties of the disk driver. */
void * pvSemaphore; /* Pointer to a Semaphore object. */
BaseType_t xBlockDeviceIsReentrant; /* Make non-zero if ffRead/ffWrite are re-entrant. */
} FF_CreationParameters_t;
/*---------- PROTOTYPES (in order of appearance). */
/* PUBLIC (Interfaces): */
FF_IOManager_t * FF_CreateIOManger( FF_CreationParameters_t * pxParameters,
FF_Error_t * pError );
FF_Error_t FF_DeleteIOManager( FF_IOManager_t * pxIOManager );
FF_Error_t FF_Mount( FF_Disk_t * pxDisk,
BaseType_t xPartitionNumber );
FF_Error_t FF_Unmount( FF_Disk_t * pxDisk );
FF_Error_t FF_FlushCache( FF_IOManager_t * pxIOManager );
static portINLINE BaseType_t FF_Mounted( FF_IOManager_t * pxIOManager )
{
return pxIOManager && pxIOManager->xPartition.ucPartitionMounted;
}
int32_t FF_GetPartitionBlockSize( FF_IOManager_t * pxIOManager );
#if ( ffconfig64_NUM_SUPPORT != 0 )
uint64_t FF_GetVolumeSize( FF_IOManager_t * pxIOManager );
#else
uint32_t FF_GetVolumeSize( FF_IOManager_t * pxIOManager );
#endif
/* PUBLIC (To FreeRTOS+FAT Only): */
int32_t FF_BlockRead( FF_IOManager_t * pxIOManager,
uint32_t ulSectorLBA,
uint32_t ulNumSectors,
void * pBuffer,
BaseType_t aSemLocked );
int32_t FF_BlockWrite( FF_IOManager_t * pxIOManager,
uint32_t ulSectorLBA,
uint32_t ulNumSectors,
void * pBuffer,
BaseType_t aSemLocked );
FF_Error_t FF_IncreaseFreeClusters( FF_IOManager_t * pxIOManager,
uint32_t Count );
FF_Error_t FF_DecreaseFreeClusters( FF_IOManager_t * pxIOManager,
uint32_t Count );
FF_Buffer_t * FF_GetBuffer( FF_IOManager_t * pxIOManager,
uint32_t ulSector,
uint8_t Mode );
FF_Error_t FF_ReleaseBuffer( FF_IOManager_t * pxIOManager,
FF_Buffer_t * pBuffer );
/* 'Internal' to FreeRTOS+FAT. */
typedef struct _SPart
{
uint32_t ulStartLBA; /* FF_FAT_PTBL_LBA */
uint32_t ulSectorCount; /* FF_FAT_PTBL_SECT_COUNT */
uint32_t
ucActive : 8, /* FF_FAT_PTBL_ACTIVE */
ucPartitionID : 8, /* FF_FAT_PTBL_ID */
bIsExtended : 1;
} FF_Part_t;
typedef struct _SPartFound
{
int iCount;
FF_Part_t pxPartitions[ ffconfigMAX_PARTITIONS ];
} FF_SPartFound_t;
/* This function will parse the 4 entries in a partition table: */
void FF_ReadParts( uint8_t * pucBuffer,
FF_Part_t * pxParts );
/* FF_PartitionCount() has now been replaced by FF_PartitionSearch()
* It will enumerate all valid partitions found
* If sector-0 happens to be a valid MBR, 1 partition will be returned
*/
FF_Error_t FF_PartitionSearch( FF_IOManager_t * pxIOManager,
FF_SPartFound_t * pPartsFound );
/* HT : for debugging only. */
BaseType_t xIsFatSector( FF_IOManager_t * pxIOManager,
uint32_t ulSectorNr );
BaseType_t xNeedLogging( FF_IOManager_t * pxIOManager );
BaseType_t xIsRootDirSector( FF_IOManager_t * pxIOManager,
uint32_t ulSectorNr );
const char * pcSectorType( FF_IOManager_t * pxIOManager,
uint32_t ulSectorNr );
/* Needed to make this public/private to be used in FF_Partition/FF_Format. */
void FF_IOMAN_InitBufferDescriptors( FF_IOManager_t * pxIOManager );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ifndef _FF_IOMAN_H_ */

View File

@ -0,0 +1,94 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_locking.h
* @ingroup LOCKING
**/
#ifndef _FF_LOCKING_H_
#define _FF_LOCKING_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h>
/*---------- PROTOTYPES (in order of appearance). */
/* PUBLIC: */
/* PRIVATE: */
void FF_PendSemaphore( void * pSemaphore );
BaseType_t FF_TrySemaphore( void * pSemaphore,
uint32_t TimeMs );
void FF_ReleaseSemaphore( void * pSemaphore );
void FF_Sleep( uint32_t TimeMs );
/* Create an event group and bind it to an I/O manager. */
BaseType_t FF_CreateEvents( FF_IOManager_t * pxIOManager );
/* Delete an event group. */
void FF_DeleteEvents( FF_IOManager_t * pxIOManager );
/* Get a lock on all DIR operations for a given I/O manager. */
void FF_LockDirectory( FF_IOManager_t * pxIOManager );
/* Release the lock on all DIR operations. */
void FF_UnlockDirectory( FF_IOManager_t * pxIOManager );
/* Get a lock on all FAT operations for a given I/O manager. */
void FF_LockFAT( FF_IOManager_t * pxIOManager );
/* Release the lock on all FAT operations. */
void FF_UnlockFAT( FF_IOManager_t * pxIOManager );
/* Called from FF_GetBuffer() as long as no buffer is available. */
BaseType_t FF_BufferWait( FF_IOManager_t * pxIOManager,
uint32_t xWaitMS );
/* Called from FF_ReleaseBuffer(). */
void FF_BufferProceed( FF_IOManager_t * pxIOManager );
/* Check if the current task already has locked the FAT. */
int FF_Has_Lock( FF_IOManager_t * pxIOManager,
uint32_t aBits );
/*
* Throw a configASSERT() in case the FAT has not been locked
* by this task.
*/
/* _HT_ This function is only necessary while testing. */
void FF_Assert_Lock( FF_IOManager_t * pxIOManager,
uint32_t aBits );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _FF_LOCKING_H_ */

View File

@ -0,0 +1,187 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_memory.h
* @ingroup MEMORY
**/
#ifndef _FF_MEMORY_H_
#define _FF_MEMORY_H_
/*
* When sector data is written or analysed, some values might be stored unaligned.
* The routines below treat all values as little arrays of either 2 or 4 bytes.
* Also on big endian platforms, the order of bytes will be swapped.
*/
/*---------- PROTOTYPES */
#if ( ffconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN )
/*
* FAT is little endian.
* On a little endian CPU, bytes will be copied to the structures below 1-to-1 :
*/
typedef struct
{
uint8_t u8_0; /* the first byte */
uint8_t u8_1; /* the second byte */
} FF_TShort_t;
typedef struct
{
uint8_t u8_0;
uint8_t u8_1;
uint8_t u8_2;
uint8_t u8_3;
} FF_TLong_t;
#elif ( ffconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN )
/*
* On a big endian CPU, all bytes will be swapped, either 2 or 4 bytes:
*/
typedef struct
{
uint8_t u8_1; /* the second byte */
uint8_t u8_0; /* the first byte */
} FF_TShort_t;
typedef struct
{
uint8_t u8_3;
uint8_t u8_2;
uint8_t u8_1;
uint8_t u8_0;
} FF_TLong_t;
#else /* if ( ffconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
#error Little or Big Endian? - Please set ffconfigBYTE_ORDER to either pdFREERTOS_LITTLE_ENDIAN or pdFREERTOS_BIG_ENDIAN 1 in FreeRTOSFATConfig.h
#endif /* if ( ffconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN ) */
/*! 16-bit union. */
typedef union
{
uint16_t u16;
FF_TShort_t bytes;
} FF_T_UN16;
/*! 32-bit union. */
typedef union
{
uint32_t u32;
FF_TLong_t bytes;
} FF_T_UN32;
/* HT inlined these functions:
*/
#if ( ffconfigINLINE_MEMORY_ACCESS != 0 )
static portINLINE uint8_t FF_getChar( const uint8_t * pBuffer,
uint32_t aOffset )
{
return ( uint8_t ) ( pBuffer[ aOffset ] );
}
static portINLINE uint16_t FF_getShort( const uint8_t * pBuffer,
uint32_t aOffset )
{
FF_T_UN16 u16;
pBuffer += aOffset;
u16.bytes.u8_1 = pBuffer[ 1 ];
u16.bytes.u8_0 = pBuffer[ 0 ];
return u16.u16;
}
static portINLINE uint32_t FF_getLong( const uint8_t * pBuffer,
uint32_t aOffset )
{
FF_T_UN32 u32;
pBuffer += aOffset;
u32.bytes.u8_3 = pBuffer[ 3 ];
u32.bytes.u8_2 = pBuffer[ 2 ];
u32.bytes.u8_1 = pBuffer[ 1 ];
u32.bytes.u8_0 = pBuffer[ 0 ];
return u32.u32;
}
static portINLINE void FF_putChar( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value )
{
pBuffer[ aOffset ] = ( uint8_t ) Value;
}
static portINLINE void FF_putShort( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value )
{
FF_T_UN16 u16;
u16.u16 = ( uint16_t ) Value;
pBuffer += aOffset;
pBuffer[ 0 ] = u16.bytes.u8_0;
pBuffer[ 1 ] = u16.bytes.u8_1;
}
static portINLINE void FF_putLong( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value )
{
FF_T_UN32 u32;
u32.u32 = Value;
pBuffer += aOffset;
pBuffer[ 0 ] = u32.bytes.u8_0;
pBuffer[ 1 ] = u32.bytes.u8_1;
pBuffer[ 2 ] = u32.bytes.u8_2;
pBuffer[ 3 ] = u32.bytes.u8_3;
}
#else /* ffconfigINLINE_MEMORY_ACCESS */
uint8_t FF_getChar( const uint8_t * pBuffer,
uint32_t aOffset );
uint16_t FF_getShort( const uint8_t * pBuffer,
uint32_t aOffset );
uint32_t FF_getLong( const uint8_t * pBuffer,
uint32_t aOffset );
void FF_putChar( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value );
void FF_putShort( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value );
void FF_putLong( uint8_t * pBuffer,
uint32_t aOffset,
uint32_t Value );
#endif /* ffconfigINLINE_MEMORY_ACCESS */
#endif /* _FF_MEMORY_H_ */

View File

@ -0,0 +1,256 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* As of 15/3/2015 all +FAT configuration items changed their prefix,
* e.g. FF_LITTLE_ENDIAN has become ffconfigLITTLE_ENDIAN
* This tempoary header file checks for the presence old configuration items
* and issue a compiler error if any is defined.
*/
#ifdef FF_LITTLE_ENDIAN
#error FF_LITTLE_ENDIAN was dropped and replaced with 'ffconfigBYTE_ORDER == pdFREERTOS_LITTLE_ENDIAN'
#endif
#ifdef FF_BIG_ENDIAN
#error FF_BIG_ENDIAN was dropped and replaced with 'ffconfigBYTE_ORDER == pdFREERTOS_BIG_ENDIAN'
#endif
#ifdef ffconfigLITTLE_ENDIAN
#error ffconfigLITTLE_ENDIAN was dropped.
#endif
#ifdef ffconfigBIG_ENDIAN
#error ffconfigBIG_ENDIAN was dropped.
#endif
#ifdef FF_HAS_CWD
#error FF_HAS_CWD still defined. Please use ffconfig prefix.
#endif
#if !defined( pdFREERTOS_LITTLE_ENDIAN ) || !defined( pdFREERTOS_BIG_ENDIAN )
#error Missing defines from FreeRTOS
#endif
#ifdef FF_LFN_SUPPORT
#error FF_LFN_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_INCLUDE_SHORT_NAME
#error FF_INCLUDE_SHORT_NAME still defined. Please use ffconfig prefix.
#endif
#ifdef FF_SHORTNAME_CASE
#error FF_SHORTNAME_CASE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_UNICODE_UTF16_SUPPORT
#error FF_UNICODE_UTF16_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_UNICODE_UTF8_SUPPORT
#error FF_UNICODE_UTF8_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FAT12_SUPPORT
#error FF_FAT12_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_OPTIMISE_UNALIGNED_ACCESS
#error FF_OPTIMISE_UNALIGNED_ACCESS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_CACHE_WRITE_THROUGH
#error FF_CACHE_WRITE_THROUGH still defined. Please use ffconfig prefix.
#endif
#ifdef FF_WRITE_BOTH_FATS
#error FF_WRITE_BOTH_FATS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_WRITE_FREE_COUNT
#error FF_WRITE_FREE_COUNT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_TIME_SUPPORT
#error FF_TIME_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_REMOVABLE_MEDIA
#error FF_REMOVABLE_MEDIA still defined. Please use ffconfig prefix.
#endif
#ifdef FF_MOUNT_FIND_FREE
#error FF_MOUNT_FIND_FREE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FINDAPI_ALLOW_WILDCARDS
#error FF_FINDAPI_ALLOW_WILDCARDS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_WILDCARD_CASE_INSENSITIVE
#error FF_WILDCARD_CASE_INSENSITIVE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_PATH_CACHE
#error FF_PATH_CACHE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_PATH_CACHE_DEPTH
#error FF_PATH_CACHE_DEPTH still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HASH_CACHE
#error FF_HASH_CACHE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HASH_FUNCTION
#error FF_HASH_FUNCTION still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HASH_TABLE_SIZE
#error FF_HASH_TABLE_SIZE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HASH_TABLE_SIZE
#error FF_HASH_TABLE_SIZE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_MKDIR_RECURSIVE
#error FF_MKDIR_RECURSIVE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_BLKDEV_USES_SEM
#error FF_BLKDEV_USES_SEM is not used any more
#endif
#ifdef ffconfigBLKDEV_USES_SEM
#error ffconfigBLKDEV_USES_SEM is not used any more
#endif
#ifdef FF_MALLOC
#error FF_MALLOC still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FREE
#error FF_FREE still defined. Please use ffconfig prefix.
#endif
#ifdef FF_64_NUM_SUPPORT
#error FF_64_NUM_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_MAX_PARTITIONS
#error FF_MAX_PARTITIONS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_MAX_FILE_SYS
#error FF_MAX_FILE_SYS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_DRIVER_BUSY_SLEEP_MS
#error FF_DRIVER_BUSY_SLEEP_MS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FPRINTF_SUPPORT
#error FF_FPRINTF_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FPRINTF_BUFFER_LENGTH
#error FF_FPRINTF_BUFFER_LENGTH still defined. Please use ffconfig prefix.
#endif
#ifdef FF_DEBUG
#error FF_DEBUG still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HAS_FUNCTION_TAB
#error FF_HAS_FUNCTION_TAB still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FAT_CHECK
#error FF_FAT_CHECK still defined. Please use ffconfig prefix.
#endif
#ifdef FF_MAX_FILENAME
#error FF_MAX_FILENAME still defined. Please use ffconfig prefix.
#endif
#ifdef FF_PRINTFFF_PRINTF
#error FF_PRINTFFF_PRINTF still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FAT_USES_STAT
#error FF_FAT_USES_STAT still defined. Please use ffconfig prefix.
#endif
#ifdef BUF_STORE_COUNT
#error BUF_STORE_COUNT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_USE_NOTIFY
#error FF_USE_NOTIFY still defined. Please use ffconfig prefix.
#endif
#ifdef FF_DEV_SUPPORT
#error FF_DEV_SUPPORT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_FSINFO_TRUSTED
#error FF_FSINFO_TRUSTED still defined. Please use ffconfig prefix.
#endif
#ifdef FF_LONG_ERR_MSG
#error FF_LONG_ERR_MSG still defined. Please use ffconfig prefix.
#endif
#ifdef FF_INLINE_MEMORY_ACCESS
#error FF_INLINE_MEMORY_ACCESS still defined. Please use ffconfig prefix.
#endif
#ifdef FF_MIRROR_FATS_UMOUNT
#error FF_MIRROR_FATS_UMOUNT still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HASH_CACHE_DEPTH
#error FF_HASH_CACHE_DEPTH still defined. Please use ffconfig prefix.
#endif
#ifdef FF_HASH_TABLE_SUPPORT
#error FF_HASH_TABLE_SUPPORT was dropped
#endif
#ifdef FF_INLINE_BLOCK_CALCULATIONS
#error FF_INLINE_BLOCK_CALCULATIONS was dropped
#endif
#ifdef FF_CWD_THREAD_LOCAL_INDEX
#error FF_CWD_THREAD_LOCAL_INDEX is now called ffconfigCWD_THREAD_LOCAL_INDEX
#endif
#ifdef FF_DEV_PATH
#error FF_DEV_PATH was dropped
#endif

View File

@ -0,0 +1,383 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* ff_stdio.h
*
* An front-end which make +FAT look like the well-known stdio-functions
*/
#ifndef FF_STDIO_H
#define FF_STDIO_H
#if defined( __WIN32__ )
#include <dir.h>
#endif
/* Standard includes. */
#include <stdio.h>
#include <stdarg.h>
/* FreeRTOS+FAT includes. */
#include "ff_headers.h"
#include "ff_sys.h"
#if ( ffconfigDEV_SUPPORT != 0 )
#include "ff_devices.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Error return from some functions. */
#define FF_EOF ( -1 )
/* Bits used in the FF_Stat_t structure. */
#define FF_IFDIR 0040000u /* directory */
#define FF_IFCHR 0020000u /* character special */
#define FF_IFBLK 0060000u /* block special */
#define FF_IFREG 0100000u /* regular */
/* Bits used in the FF_FindData_t structure. */
#define FF_FA_NORMAL 0x00
#define FF_FA_RDONLY 0x01
#define FF_FA_HIDDEN 0x02
#define FF_FA_SYSTEM 0x04
#define FF_FA_LABEL 0x08
#define FF_FA_DIREC 0x10
#define FF_FA_ARCH 0x20
/* FreeRTOS+FAT uses three thread local buffers. The first stores errno, the
* second a pointer to the CWD structure (if one is used), and the third the more
* descriptive error code. */
#define stdioERRNO_THREAD_LOCAL_OFFSET ( ffconfigCWD_THREAD_LOCAL_INDEX + 0 )
#define stdioCWD_THREAD_LOCAL_OFFSET ( ffconfigCWD_THREAD_LOCAL_INDEX + 1 )
#define stdioFF_ERROR_THREAD_LOCAL_OFFSET ( ffconfigCWD_THREAD_LOCAL_INDEX + 2 )
/* Structure used with ff_stat(). */
typedef struct FF_STAT
{
uint32_t st_ino; /* First data cluster number. */
uint32_t st_size; /* Size of the object in number of bytes. */
uint16_t st_dev; /* The device on which the file can be found (see ff_sys.c) */
uint16_t st_mode; /* The mode (attribute bits) of this file or directory. */
#if ( ffconfigTIME_SUPPORT == 1 )
uint32_t st_atime;
uint32_t st_mtime;
uint32_t st_ctime;
#endif /* ffconfigTIME_SUPPORT */
} FF_Stat_t;
/* Structure used with ff_findfirst(), ff_findnext(), etc. */
typedef struct
{
/* private */
UBaseType_t
#if ( ffconfigDEV_SUPPORT != 0 )
bIsDeviceDir : 1,
#endif
bEntryPOwner : 1;
struct FF_DIR_HANDLER xDirectoryHandler;
FF_DirEnt_t xDirectoryEntry;
/* Public fields included so FF_DirEnt_t does not need to be public. */
const char * pcFileName;
uint32_t ulFileSize;
uint8_t ucAttributes;
} FF_FindData_t;
/*-----------------------------------------------------------
* Get and set the task's file system errno
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
/*
* int FF_GetErrno( void );
* void FF_SetErrno( int ff_errno );
*
* _RB_ comments are incorrect and index should use the stdioERRNO_THREAD_LOCAL_OFFSET offset.
*/
/* The errno is stored in a thread local buffer. */
static portINLINE void stdioSET_ERRNO( int iErrno )
{
vTaskSetThreadLocalStoragePointer( NULL, ffconfigCWD_THREAD_LOCAL_INDEX, ( void * ) ( iErrno ) );
}
static portINLINE int stdioGET_ERRNO( void )
{
void * pvResult;
pvResult = pvTaskGetThreadLocalStoragePointer( ( TaskHandle_t ) NULL, ffconfigCWD_THREAD_LOCAL_INDEX );
return ( int ) pvResult;
}
#if ( ( configNUM_THREAD_LOCAL_STORAGE_POINTERS - ffconfigCWD_THREAD_LOCAL_INDEX ) < 3 )
#error Please define space for 3 entries
#endif
/*
* Store the FreeRTOS+FAT error code, which provides more detail than errno.
*/
static portINLINE void stdioSET_FF_ERROR( FF_Error_t iFF_ERROR )
{
vTaskSetThreadLocalStoragePointer( NULL, stdioFF_ERROR_THREAD_LOCAL_OFFSET, ( void * ) ( iFF_ERROR ) );
}
/*
* Read back the FreeRTOS+FAT error code, which provides more detail than
* errno.
*/
static portINLINE FF_Error_t stdioGET_FF_ERROR( void )
{
void * pvResult;
pvResult = pvTaskGetThreadLocalStoragePointer( NULL, stdioFF_ERROR_THREAD_LOCAL_OFFSET );
return ( FF_Error_t ) pvResult;
}
/*-----------------------------------------------------------
* Open and close a file
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
FF_FILE * ff_fopen( const char * pcFile,
const char * pcMode );
int ff_fclose( FF_FILE * pxStream );
/*-----------------------------------------------------------
* Seek and tell
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_fseek( FF_FILE * pxStream,
long lOffset,
int iWhence );
void ff_rewind( FF_FILE * pxStream );
long ff_ftell( FF_FILE * pxStream );
int ff_feof( FF_FILE * pxStream );
/*-----------------------------------------------------------
* Read and write
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
size_t ff_fread( void * pvBuffer,
size_t xSize,
size_t xItems,
FF_FILE * pxStream );
size_t ff_fwrite( const void * pvBuffer,
size_t xSize,
size_t xItems,
FF_FILE * pxStream );
/* Whenever possible, use ellipsis parameter type checking.
* _RB_ Compiler specifics need to be moved to the compiler specific header files. */
#if defined( __GNUC__ )
/* The GNU-C compiler will check if the parameters are correct. */
int ff_fprintf( FF_FILE * pxStream,
const char * pcFormat,
... )
__attribute__( ( format( __printf__, 2, 3 ) ) );
#else
int ff_fprintf( FF_FILE * pxStream,
const char * pcFormat,
... );
#endif
int ff_fgetc( FF_FILE * pxStream );
int ff_fputc( int iChar,
FF_FILE * pxStream );
char * ff_fgets( char * pcBuffer,
size_t xCount,
FF_FILE * pxStream );
/*-----------------------------------------------------------
* Change length of file (truncate)
* File should have been opened in "w" or "a" mode
* The actual length of the file will be made equal to the current writing
* position
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_seteof( FF_FILE * pxStream );
/*-----------------------------------------------------------
* Open a file in append/update mode, truncate its length to a given value,
* or write zero's up until the required length, and return a handle to the open
* file. If NULL is returned, ff_errno contains an error code.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
FF_FILE * ff_truncate( const char * pcFileName,
long lTruncateSize );
/*-----------------------------------------------------------
* Flush to disk
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_fflush( FF_FILE * pxStream );
/*-----------------------------------------------------------
* Create directory, remove and rename files
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
#if ( ffconfigMKDIR_RECURSIVE == 0 )
int ff_mkdir( const char * pcPath );
#else
/* If the parameter bRecursive is non-zero, the entire path will be checked
* and if necessary, created. */
int ff_mkdir( const char * pcPath,
int bRecursive );
#endif
/*-----------------------------------------------------------
* Create path specified by the pcPath parameter.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_mkpath( const char * pcPath );
/*-----------------------------------------------------------
* Remove the directory specified by the pcDirectory parameter.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_rmdir( const char * pcDirectory );
/*-----------------------------------------------------------
* Delete a directory and, recursively, all of its contents.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
#if ( ffconfigUSE_DELTREE != 0 )
/* By default, this function will not be compiled. The function will
* recursively call itself, which is against the FreeRTOS coding standards, so
* IT MUST BE USED WITH CARE.
*
* The cost of each recursion will be roughly:
* Stack : 48 (12 stack words)
* Heap : 112 + ffconfigMAX_FILENAME
* These numbers may change depending on CPU and compiler. */
int ff_deltree( const char * pcPath );
#endif
/*-----------------------------------------------------------
* Remove/delete a file.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_remove( const char * pcPath );
/*-----------------------------------------------------------
* Move a file, also cross-directory but not across a file system.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_rename( const char * pcOldName,
const char * pcNewName,
int bDeleteIfExists );
/*-----------------------------------------------------------
* Get the status of a file.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
int ff_stat( const char * pcFileName,
FF_Stat_t * pxStatBuffer );
/* _HT_ Keep this for a while, until the new ff_stat() is wel tested */
int ff_old_stat( const char * pcName,
FF_Stat_t * pxStatBuffer );
/*-----------------------------------------------------------
* Get the length of a file in bytes.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
size_t ff_filelength( FF_FILE * pxFile );
/*-----------------------------------------------------------
* Working directory and iterating through directories.
* The most up to date API documentation is currently provided on the following URL:
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_FAT/Standard_File_System_API.html
*-----------------------------------------------------------*/
#if ffconfigHAS_CWD
int ff_chdir( const char * pcDirectoryName );
char * ff_getcwd( char * pcBuffer,
size_t xBufferLength );
#endif
int ff_findfirst( const char * pcDirectory,
FF_FindData_t * pxFindData );
int ff_findnext( FF_FindData_t * pxFindData );
int ff_isdirempty( const char * pcPath );
/* _RB_ What to do regarding documentation for the definitions below here. */
#if ( ffconfig64_NUM_SUPPORT != 0 )
int64_t ff_diskfree( const char * pcPath,
uint32_t * pxSectorCount );
#else
int32_t ff_diskfree( const char * pcPath,
uint32_t * pxSectorCount );
#endif
int ff_finddir( const char * pcPath );
#if ( ffconfigHAS_CWD == 1 )
/* Obtain the CWD used by the current task. */
void ff_free_CWD_space( void );
#endif
typedef enum _EFileAction
{
eFileCreate,
eFileRemove,
eFileChange,
eFileIsDir = 0x80,
} eFileAction_t;
void callFileEvents( const char * apPath,
eFileAction_t aAction );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* FF_STDIO_H */

View File

@ -0,0 +1,139 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_string.c
* @ingroup STRING
*
* @defgroup STRING FreeRTOS+FAT String Library
* @brief Portable String Library for FreeRTOS+FAT
*
*
**/
#ifndef _FF_STRING_H_
#define _FF_STRING_H_
#include "FreeRTOSFATConfig.h"
#include <string.h>
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
#include <wchar.h>
typedef wchar_t FF_T_WCHAR; /*/< Unicode UTF-16 Character type, for FreeRTOS+FAT when UNICODE is enabled. */
#endif
#if defined( _MSC_VER ) && ( _MSC_VER <= 1600 )
#define FF_stricmp _stricmp
#else
#define FF_stricmp strcasecmp
#endif
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
void FF_tolower( FF_T_WCHAR * string,
uint32_t strLen );
void FF_toupper( FF_T_WCHAR * string,
uint32_t strLen );
BaseType_t FF_strmatch( const FF_T_WCHAR * str1,
const FF_T_WCHAR * str2,
BaseType_t len );
FF_T_WCHAR * FF_strtok( const FF_T_WCHAR * string,
FF_T_WCHAR * token,
uint16_t * tokenNumber,
BaseType_t * last,
BaseType_t xLength );
BaseType_t FF_wildcompare( const FF_T_WCHAR * pcWildCard,
const FF_T_WCHAR * pszString );
/* ASCII to UTF16 and UTF16 to ASCII routines. -- These are lossy routines, and are only for converting ASCII to UTF-16 */
/* and the equivalent back to ASCII. Do not use them for international text. */
void FF_cstrtowcs( FF_T_WCHAR * wcsDest,
const char * szpSource );
void FF_wcstocstr( char * szpDest,
const FF_T_WCHAR * wcsSource );
void FF_cstrntowcs( FF_T_WCHAR * wcsDest,
const char * szpSource,
uint32_t len );
void FF_wcsntocstr( char * szpDest,
const FF_T_WCHAR * wcsSource,
uint32_t len );
#else /* if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) */
void FF_tolower( char * string,
uint32_t strLen );
void FF_toupper( char * string,
uint32_t strLen );
BaseType_t FF_strmatch( const char * str1,
const char * str2,
BaseType_t len );
char * FF_strtok( const char * string,
char * token,
uint16_t * tokenNumber,
BaseType_t * last,
BaseType_t xLength );
BaseType_t FF_wildcompare( const char * pcWildCard,
const char * pszString );
#endif /* ffconfigUNICODE_UTF16_SUPPORT */
/* UTF8 / UTF16 Transformation Functions. */
#if ( ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF ) ) || ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
UBaseType_t FF_GetUtf16SequenceLen( uint16_t usLeadChar );
#endif
#if ( ffconfigUNICODE_UTF8_SUPPORT != 0 )
int32_t FF_Utf8ctoUtf16c( uint16_t * utf16Dest,
const uint8_t * utf8Source,
uint32_t ulSize );
int32_t FF_Utf16ctoUtf8c( uint8_t * utf8Dest,
const uint16_t * utf16Source,
uint32_t ulSize );
#endif /* ffconfigUNICODE_UTF8_SUPPORT */
/* UTF16 / UTF32 Transformation Functions. */
#if ( ffconfigNOT_USED_FOR_NOW != 0 )
int32_t FF_Utf16ctoUtf32c( uint32_t * utf32Dest,
const uint16_t * utf16Source );
#endif
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 ) && ( WCHAR_MAX > 0xFFFF )
int32_t FF_Utf32ctoUtf16c( uint16_t * utf16Dest,
uint32_t utf32char,
uint32_t ulSize );
#endif
/* String transformations. */
int32_t FF_Utf32stoUtf8s( uint8_t * Utf8String,
uint32_t * Utf32String );
#if ( ffconfigUNICODE_UTF16_SUPPORT != 0 )
#define STRNCPY( target, src, maxlen ) wcsncpy( ( target ), ( src ), ( maxlen ) )
#define STRLEN( string ) wcslen( ( string ) )
#else
#define STRNCPY( target, src, maxlen ) strncpy( ( target ), ( src ), ( maxlen ) );
#define STRLEN( string ) strlen( ( string ) )
#endif
#endif /* ifndef _FF_STRING_H_ */

View File

@ -0,0 +1,133 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* ff_sys.h
*
* This module allow to map several separate file-sub-systems into a root directory
*
* For instance, a system with 3 sub sytems:
*
* /flash : NAND flash driver
* /ram : RAM-disk driver
* / : SD-card driver
*
* In this example, the SD-card driver handles ALL files and directories which
* do not match /flash/ * or /ram/ *
*
* Now for instance a file call "/flash/etc/network.ini"
* will be stored as "/etc/network.ini" on the NAND drive
*
* This module along with ff_stdio.c make translations between absolute
* and relative paths
*/
#ifndef FF_SYS_H
#define FF_SYS_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct FILE_SUB_SYSTEM
{
char pcPath[ 16 ];
BaseType_t xPathlen;
FF_IOManager_t * pxManager;
} FF_SubSystem_t;
typedef struct FF_DIR_HANDLER
{
union
{
struct
{
unsigned
bEndOfDir : 1,
bFirstCalled : 1,
bIsValid : 1,
bAddDotEntries : 2;
} bits;
unsigned uFlags;
} u;
/*
* path will contain the relative path. It will be used when calling +FAT functions
* like FF_FindFirst() / FF_FindNext()
* For instance, for "/flash/etc" path will become "/etc"
*/
const char * pcPath;
FF_IOManager_t * pxManager; /* Will point to handler of this partition. */
BaseType_t xFSIndex; /* The index of this entry, where 0 always means: the root system. */
} FF_DirHandler_t;
/*
* Initialise (clear) the file system table
* This will also called by FF_FS_Add()
*/
void FF_FS_Init( void );
/*
* Add a file system
* The path must be absolute, e.g. start with a slash
* The second argument is the FF_Disk_t structure that is handling the driver
*/
int FF_FS_Add( const char * pcPath,
FF_Disk_t * pxDisk );
/*
* Remove a file system
* which ws earlier added by ff_fs_ad()
*/
void FF_FS_Remove( const char * pcPath );
/*
* Internally used by ff_stdio:
* The ff_dir_handler helps to iterate through a mounte directory
*
* FF_FS_Find() will find a ff_dir_handler for a given path
*/
int FF_FS_Find( const char * pcPath,
FF_DirHandler_t * pxHandler );
/*
* For internal use:
* Get the file system information, based on an index
*/
int FF_FS_Get( int iIndex,
FF_SubSystem_t * pxSystem );
/*
* Returns the number of registered
* file systems
*/
int FF_FS_Count( void );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* FF_SYS_H */

View File

@ -0,0 +1,86 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* @file ff_time.h
* @ingroup TIME
*
* Provides a means for receiving the time on any platform.
**/
#ifndef _FF_TIME_H_
#define _FF_TIME_H_
#include <time.h>
#include "FreeRTOSFATConfig.h"
/* _HT_
* The following declarations and functions may be moved to a common directory?
*/
typedef struct xTIME_STRUCT
{
int tm_sec; /* Seconds */
int tm_min; /* Minutes */
int tm_hour; /* Hour (0--23) */
int tm_mday; /* Day of month (1--31) */
int tm_mon; /* Month (0--11) */
int tm_year; /* Year (calendar year minus 1900) */
int tm_wday; /* Weekday (0--6; Sunday = 0) */
int tm_yday; /* Day of year (0--365) */
int tm_isdst; /* 0 if daylight savings time is not in effect) */
} FF_TimeStruct_t;
/* Equivalent of time() : returns the number of seconds after 1-1-1970. */
time_t FreeRTOS_time( time_t * pxTime );
/* Equivalent of mktime() : calculates the number of seconds after 1-1-1970. */
time_t FreeRTOS_mktime( const FF_TimeStruct_t * pxTimeBuf );
/* Equivalent of gmtime_r() : Fills a 'struct tm'. */
FF_TimeStruct_t * FreeRTOS_gmtime_r( const time_t * pxTime,
FF_TimeStruct_t * pxTimeBuf );
/**
* @public
* @brief A TIME and DATE object for FreeRTOS+FAT. A FreeRTOS+FAT time driver must populate these values.
*
**/
typedef struct
{
uint16_t Year; /* Year (e.g. 2009). */
uint16_t Month; /* Month (e.g. 1 = Jan, 12 = Dec). */
uint16_t Day; /* Day (1 - 31). */
uint16_t Hour; /* Hour (0 - 23). */
uint16_t Minute; /* Min (0 - 59). */
uint16_t Second; /* Second (0 - 59). */
} FF_SystemTime_t;
/*---------- PROTOTYPES */
int32_t FF_GetSystemTime( FF_SystemTime_t * pxTime );
#endif /* ifndef _FF_TIME_H_ */

View File

@ -0,0 +1,449 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_headers.h"
#include "ff_ramdisk.h"
#include "ff_sys.h"
#define ramHIDDEN_SECTOR_COUNT 8
#define ramPRIMARY_PARTITIONS 1
#define ramHUNDRED_64_BIT 100ULL
#define ramSECTOR_SIZE 512UL
#define ramPARTITION_NUMBER 0 /* Only a single partition is used. */
#define ramBYTES_PER_KB ( 1024ull )
#define ramSECTORS_PER_KB ( ramBYTES_PER_KB / 512ull )
/* Used as a magic number to indicate that an FF_Disk_t structure is a RAM
* disk. */
#define ramSIGNATURE 0x41404342
/*-----------------------------------------------------------*/
/*
* The function that writes to the media - as this is implementing a RAM disk
* the media is just a RAM buffer.
*/
static int32_t prvWriteRAM( uint8_t * pucBuffer,
uint32_t ulSectorNumber,
uint32_t ulSectorCount,
FF_Disk_t * pxDisk );
/*
* The function that reads from the media - as this is implementing a RAM disk
* the media is just a RAM buffer.
*/
static int32_t prvReadRAM( uint8_t * pucBuffer,
uint32_t ulSectorNumber,
uint32_t ulSectorCount,
FF_Disk_t * pxDisk );
#ifndef RAMDISK_ALREADY_PARTITIONED
/*
* This is the driver for a RAM disk. Unlike most media types, RAM disks are
* volatile so are created anew each time the system is booted. As the disk is
* new and just created, it must also be partitioned and formatted.
*/
static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t * pxDisk );
#endif
/*-----------------------------------------------------------*/
/* This is the prototype of the function used to initialise the RAM disk driver.
* Other media drivers do not have to have the same prototype.
*
* In this example:
+ pcName is the name to give the disk within FreeRTOS+FAT's virtual file system.
+ pucDataBuffer is the start of the RAM to use as the disk.
+ ulSectorCount is effectively the size of the disk, each sector is 512 bytes.
+ xIOManagerCacheSize is the size of the IO manager's cache, which must be a
+ multiple of the sector size, and at least twice as big as the sector size.
*/
FF_Disk_t * FF_RAMDiskInit( char * pcName,
uint8_t * pucDataBuffer,
uint32_t ulSectorCount,
size_t xIOManagerCacheSize )
{
FF_Error_t xError;
FF_Disk_t * pxDisk = NULL;
FF_CreationParameters_t xParameters;
/* Check the validity of the xIOManagerCacheSize parameter. */
configASSERT( ( xIOManagerCacheSize % ramSECTOR_SIZE ) == 0 );
configASSERT( ( xIOManagerCacheSize >= ( 2 * ramSECTOR_SIZE ) ) );
/* Attempt to allocated the FF_Disk_t structure. */
pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( FF_Disk_t ) );
if( pxDisk != NULL )
{
/* Start with every member of the structure set to zero. */
memset( pxDisk, '\0', sizeof( FF_Disk_t ) );
/* Clear the entire space. */
#ifndef RAMDISK_ALREADY_PARTITIONED
memset( pucDataBuffer, '\0', ulSectorCount * ramSECTOR_SIZE );
#endif
/* The pvTag member of the FF_Disk_t structure allows the structure to be
* extended to also include media specific parameters. The only media
* specific data that needs to be stored in the FF_Disk_t structure for a
* RAM disk is the location of the RAM buffer itself - so this is stored
* directly in the FF_Disk_t's pvTag member. */
pxDisk->pvTag = ( void * ) pucDataBuffer;
/* The signature is used by the disk read and disk write functions to
* ensure the disk being accessed is a RAM disk. */
pxDisk->ulSignature = ramSIGNATURE;
/* The number of sectors is recorded for bounds checking in the read and
* write functions. */
pxDisk->ulNumberOfSectors = ulSectorCount;
/* Create the IO manager that will be used to control the RAM disk. */
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.pucCacheMemory = NULL;
xParameters.ulMemorySize = xIOManagerCacheSize;
xParameters.ulSectorSize = ramSECTOR_SIZE;
xParameters.fnWriteBlocks = prvWriteRAM;
xParameters.fnReadBlocks = prvReadRAM;
xParameters.pxDisk = pxDisk;
/* Driver is reentrant so xBlockDeviceIsReentrant can be set to pdTRUE.
* In this case the semaphore is only used to protect FAT data
* structures. */
xParameters.pvSemaphore = ( void * ) xSemaphoreCreateRecursiveMutex();
xParameters.xBlockDeviceIsReentrant = pdFALSE;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xError );
if( ( pxDisk->pxIOManager != NULL ) && ( FF_isERR( xError ) == pdFALSE ) )
{
/* Record that the RAM disk has been initialised. */
pxDisk->xStatus.bIsInitialised = pdTRUE;
#ifdef RAMDISK_ALREADY_PARTITIONED
xError = FF_ERR_NONE;
#else
/* Create a partition on the RAM disk. NOTE! The disk is only
* being partitioned here because it is a new RAM disk. It is
* known that the disk has not been used before, and cannot already
* contain any partitions. Most media drivers will not perform
* this step because the media will have already been partitioned. */
xError = prvPartitionAndFormatDisk( pxDisk );
#endif
if( FF_isERR( xError ) == pdFALSE )
{
/* Record the partition number the FF_Disk_t structure is, then
* mount the partition. */
pxDisk->xStatus.bPartitionNumber = ramPARTITION_NUMBER;
/* Mount the partition. */
xError = FF_Mount( pxDisk, ramPARTITION_NUMBER );
FF_PRINTF( "FF_RAMDiskInit: FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
}
if( FF_isERR( xError ) == pdFALSE )
{
/* The partition mounted successfully, add it to the virtual
* file system - where it will appear as a directory off the file
* system's root directory. */
FF_FS_Add( pcName, pxDisk );
}
}
else
{
FF_PRINTF( "FF_RAMDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
/* The disk structure was allocated, but the disk's IO manager could
* not be allocated, so free the disk again. */
FF_RAMDiskDelete( pxDisk );
pxDisk = NULL;
}
}
else
{
FF_PRINTF( "FF_RAMDiskInit: Malloc failed\n" );
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_RAMDiskDelete( FF_Disk_t * pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return pdPASS;
}
/*-----------------------------------------------------------*/
static int32_t prvReadRAM( uint8_t * pucDestination,
uint32_t ulSectorNumber,
uint32_t ulSectorCount,
FF_Disk_t * pxDisk )
{
int32_t lReturn;
uint8_t * pucSource;
if( pxDisk != NULL )
{
if( pxDisk->ulSignature != ramSIGNATURE )
{
/* The disk structure is not valid because it doesn't contain a
* magic number written to the disk when it was created. */
lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
}
else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
{
/* The disk has not been initialised. */
lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
}
else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
{
/* The start sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
{
/* The end sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else
{
/* Obtain the pointer to the RAM buffer being used as the disk. */
pucSource = ( uint8_t * ) pxDisk->pvTag;
/* Move to the start of the sector being read. */
pucSource += ( ramSECTOR_SIZE * ulSectorNumber );
/* Copy the data from the disk. As this is a RAM disk this can be
* done using memcpy(). */
memcpy( ( void * ) pucDestination,
( void * ) pucSource,
( size_t ) ( ulSectorCount * ramSECTOR_SIZE ) );
lReturn = FF_ERR_NONE;
}
}
else
{
lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
}
return lReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvWriteRAM( uint8_t * pucSource,
uint32_t ulSectorNumber,
uint32_t ulSectorCount,
FF_Disk_t * pxDisk )
{
int32_t lReturn = FF_ERR_NONE;
uint8_t * pucDestination;
if( pxDisk != NULL )
{
if( pxDisk->ulSignature != ramSIGNATURE )
{
/* The disk structure is not valid because it doesn't contain a
* magic number written to the disk when it was created. */
lReturn = FF_ERR_IOMAN_DRIVER_FATAL_ERROR | FF_ERRFLAG;
}
else if( pxDisk->xStatus.bIsInitialised == pdFALSE )
{
/* The disk has not been initialised. */
lReturn = FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG;
}
else if( ulSectorNumber >= pxDisk->ulNumberOfSectors )
{
/* The start sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else if( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) < ulSectorCount )
{
/* The end sector is not within the bounds of the disk. */
lReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
else
{
/* Obtain the location of the RAM being used as the disk. */
pucDestination = ( uint8_t * ) pxDisk->pvTag;
/* Move to the sector being written to. */
pucDestination += ( ramSECTOR_SIZE * ulSectorNumber );
/* Write to the disk. As this is a RAM disk the write can use a
* memcpy(). */
memcpy( ( void * ) pucDestination,
( void * ) pucSource,
( size_t ) ulSectorCount * ( size_t ) ramSECTOR_SIZE );
lReturn = FF_ERR_NONE;
}
}
else
{
lReturn = FF_ERR_NULL_POINTER | FF_ERRFLAG;
}
return lReturn;
}
/*-----------------------------------------------------------*/
#ifndef RAMDISK_ALREADY_PARTITIONED
static FF_Error_t prvPartitionAndFormatDisk( FF_Disk_t * pxDisk )
{
FF_PartitionParameters_t xPartition;
FF_Error_t xError;
/* Create a single partition that fills all available space on the disk. */
memset( &xPartition, '\0', sizeof( xPartition ) );
xPartition.ulSectorCount = pxDisk->ulNumberOfSectors;
xPartition.ulHiddenSectors = ramHIDDEN_SECTOR_COUNT;
xPartition.xPrimaryCount = ramPRIMARY_PARTITIONS;
xPartition.eSizeType = eSizeIsQuota;
/* Partition the disk */
xError = FF_Partition( pxDisk, &xPartition );
FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
if( FF_isERR( xError ) == pdFALSE )
{
/* Format the partition. */
xError = FF_Format( pxDisk, ramPARTITION_NUMBER, pdTRUE, pdTRUE );
FF_PRINTF( "FF_RAMDiskInit: FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
}
return xError;
}
/*-----------------------------------------------------------*/
#endif
BaseType_t FF_RAMDiskShowPartition( FF_Disk_t * pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeKB, ulFreeSizeKB;
int iPercentageFree;
FF_IOManager_t * pxIOManager;
const char * pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
if( pxIOManager->xPartition.ulDataSectors == ( uint32_t ) 0 )
{
iPercentageFree = 0;
}
else
{
iPercentageFree = ( int ) ( ( ramHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t ) pxIOManager->xPartition.ulDataSectors ) );
}
ulTotalSizeKB = pxIOManager->xPartition.ulDataSectors / ramSECTORS_PER_KB;
ulFreeSizeKB = ( uint32_t ) ( ullFreeSectors / ramSECTORS_PER_KB );
/* It is better not to use the 64-bit format such as %Lu because it
* might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu KB\n", ulTotalSizeKB );
FF_PRINTF( "FreeSize %8lu KB ( %d perc free )\n", ulFreeSizeKB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
void FF_RAMDiskFlush( FF_Disk_t * pxDisk )
{
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != 0 ) && ( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,55 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef __RAMDISK_H__
#define __RAMDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ff_headers.h"
//#define RAMDISK_ALREADY_PARTITIONED
/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
FF_Disk_t * FF_RAMDiskInit( char * pcName,
uint8_t * pucDataBuffer,
uint32_t ulSectorCount,
size_t xIOManagerCacheSize );
/* Release all resources */
BaseType_t FF_RAMDiskDelete( FF_Disk_t * pxDisk );
/* Show some partition information */
BaseType_t FF_RAMDiskShowPartition( FF_Disk_t * pxDisk );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __RAMDISK_H__ */

View File

@ -0,0 +1,80 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef __SDDISK_H__
#define __SDDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ff_headers.h"
/* Return non-zero if the SD-card is present.
* The parameter 'pxDisk' may be null, unless device locking is necessary. */
BaseType_t FF_SDDiskDetect( FF_Disk_t * pxDisk );
/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
FF_Disk_t * FF_SDDiskInit( const char * pcName );
BaseType_t FF_SDDiskReinit( FF_Disk_t * pxDisk );
/* Unmount the volume */
BaseType_t FF_SDDiskUnmount( FF_Disk_t * pDisk );
/* Mount the volume */
BaseType_t FF_SDDiskMount( FF_Disk_t * pDisk );
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t * pDisk );
/* Show some partition information */
BaseType_t FF_SDDiskShowPartition( FF_Disk_t * pDisk );
/* Flush changes from the driver's buf to disk */
void FF_SDDiskFlush( FF_Disk_t * pDisk );
/* Format a given partition on an SD-card. */
BaseType_t FF_SDDiskFormat( FF_Disk_t * pxDisk,
BaseType_t aPart );
/* Format a given partition by name on an SD-card. */
BaseType_t FF_SDDiskFormatRemount( FF_Disk_t * pxDisk,
const char *pcName );
/* Return non-zero if an SD-card is detected in a given slot. */
BaseType_t FF_SDDiskInserted( BaseType_t xDriveNr );
/* _RB_ Temporary function - ideally the application would not need the IO
* manageer structure, just a handle to a disk. */
FF_IOManager_t * sddisk_ioman( FF_Disk_t * pxDisk );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SDDISK_H__ */

View File

@ -0,0 +1,73 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef __SFDISK_H__
#define __SFDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ff_headers.h"
/* Return non-zero if the spi-flash is present.
* The parameter 'pxDisk' may be null, unless device locking is necessary. */
BaseType_t FF_SFDiskDetect( FF_Disk_t * pxDisk );
/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
FF_Disk_t * FF_SFDiskInit( const char * pcName );
BaseType_t FF_SFDiskReinit( FF_Disk_t * pxDisk );
/* Unmount the volume */
BaseType_t FF_SFDiskUnmount( FF_Disk_t * pDisk );
/* Mount the volume */
BaseType_t FF_SFDiskMount( FF_Disk_t * pDisk );
/* Release all resources */
BaseType_t FF_SFDiskDelete( FF_Disk_t * pDisk );
/* Show some partition information */
BaseType_t FF_SFDiskShowPartition( FF_Disk_t * pDisk );
/* Flush changes from the driver's buf to disk */
void FF_SFDiskFlush( FF_Disk_t * pDisk );
/* Format a given partition on an spi-flash. */
BaseType_t FF_SFDiskFormat( FF_Disk_t * pxDisk,
BaseType_t aPart );
/* Return non-zero if an spi-flash is detected in a given slot. */
BaseType_t FF_SFDiskInserted( BaseType_t xDriveNr );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __SFDISK_H__ */

View File

@ -0,0 +1,77 @@
/*
* FreeRTOS+FAT V2.3.3
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef __USBDISK_H__
#define __USBDISK_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "ff_headers.h"
/* Return non-zero if the SD-card is present.
* The parameter 'pxDisk' may be null, unless device locking is necessary. */
BaseType_t FF_USBDiskDetect( FF_Disk_t * pxDisk );
/* Create a RAM disk, supplying enough memory to hold N sectors of 512 bytes each */
FF_Disk_t * FF_USBDiskInit( const char * pcName );
BaseType_t FF_USBDiskReinit( FF_Disk_t * pxDisk );
/* Unmount the volume */
BaseType_t FF_USBDiskUnmount( FF_Disk_t * pDisk );
/* Mount the volume */
BaseType_t FF_USBDiskMount( FF_Disk_t * pDisk );
/* Release all resources */
BaseType_t FF_USBDiskDelete( FF_Disk_t * pDisk );
/* Show some partition information */
BaseType_t FF_USBDiskShowPartition( FF_Disk_t * pDisk );
/* Flush changes from the driver's buf to disk */
void FF_USBDiskFlush( FF_Disk_t * pDisk );
/* Format a given partition on an SD-card. */
BaseType_t FF_USBDiskFormat( FF_Disk_t * pxDisk,
BaseType_t aPart );
/* Return non-zero if an SD-card is detected in a given slot. */
BaseType_t FF_USBDiskInserted( BaseType_t xDriveNr );
/* _RB_ Temporary function - ideally the application would not need the IO
* manageer structure, just a handle to a disk. */
FF_IOManager_t * usbdisk_ioman( FF_Disk_t * pxDisk );
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __USBDISK_H__ */

View File

@ -0,0 +1,710 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* 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.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* LPC18xx includes. */
#include "chip.h"
#include "board.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_sddisk.h"
#include "ff_sys.h"
#include "mmcsd_core.h"
/* Misc definitions. */
#define sdSIGNATURE 0x41404342UL
#define sdHUNDRED_64_BIT ( 100ull )
#define sdBYTES_PER_MB ( 1024ull * 1024ull )
#define sdSECTORS_PER_MB ( sdBYTES_PER_MB / 512ull )
#define sdIOMAN_MEM_SIZE 4096
#define sdAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 )
/*-----------------------------------------------------------*/
/*_RB_ Functions require comment blocks. */
static int32_t prvSDMMC_Init( void );
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
/*-----------------------------------------------------------*/
/*_RB_ Variables require a comment block where appropriate. */
static struct mmcsd_card *xCardInfo;
static BaseType_t xSDCardStatus;
static SemaphoreHandle_t xPlusFATMutex;
/*-----------------------------------------------------------*/
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
/*_RB_ Many of the comments in this file apply to other functions in the file. */
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
#if DEVICE_TYPE_SELECT == EMMC_FLASH
iReturn = mmcsd_req_blk( xCardInfo, ulSectorNumber + OTA_MEDIA_OFFSET / 512, pucBuffer, ulSectorCount, 0 );
#else
iReturn = mmcsd_req_blk( xCardInfo, ulSectorNumber, pucBuffer, ulSectorCount, 0 );
#endif
/*_RB_ I'm guessing 512 is a sector size, but that needs to be clear.
Is it defined in a header somewhere? If so we can do a search and
replace in files on it as it seems to be used everywhere. */
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
/*_RB_ Signed number used to return bitmap (again below). */
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised != 0 )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
if( ( pxDisk != NULL ) &&
( xSDCardStatus == pdPASS ) &&
( pxDisk->ulSignature == sdSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
#if DEVICE_TYPE_SELECT == EMMC_FLASH
iReturn = mmcsd_req_blk( xCardInfo, ulSectorNumber + OTA_MEDIA_OFFSET / 512, pucBuffer, ulSectorCount, 1 );
#else
iReturn = mmcsd_req_blk( xCardInfo, ulSectorNumber, pucBuffer, ulSectorCount, 1 );
#endif
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised )
{
FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
void FF_SDDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
#if DEVICE_TYPE_SELECT == EMMC_FLASH
#define emmcSECTOR_SIZE 512
#define emmcHIDDEN_SECTOR_COUNT 8
#define emmcPRIMARY_PARTITIONS 1
#define emmcPARTITION_NUMBER 0 /* Only a single partition is used. */
static FF_Error_t PartitionAndFormatEmmcDisk( FF_Disk_t * pxDisk )
{
FF_PartitionParameters_t xPartition;
FF_Error_t xError;
/* Create a single partition that fills all available space on the disk. */
memset( &xPartition, '\0', sizeof( xPartition ) );
xPartition.ulSectorCount = OTA_MEDIA_SIZE / emmcSECTOR_SIZE;
xPartition.ulHiddenSectors = emmcHIDDEN_SECTOR_COUNT;
xPartition.xPrimaryCount = emmcPRIMARY_PARTITIONS;
xPartition.eSizeType = eSizeIsQuota;
/* Partition the disk */
xError = FF_Partition( pxDisk, &xPartition );
FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
if( FF_isERR( xError ) == pdFALSE )
{
/* Format the partition. */
xError = FF_Format( pxDisk, emmcPARTITION_NUMBER, pdFALSE, pdFALSE );
FF_PRINTF( "FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
if ( FF_isERR( xError ) == pdFALSE )
{
xError = FF_Mount( pxDisk, 0 );
FF_PRINTF( "FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
FF_SDDiskShowPartition( pxDisk );
}
}
return xError;
}
#endif
/* Initialise the SDIO driver and mount an SD card */
FF_Disk_t *FF_SDDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t * pxDisk;
xSDCardStatus = prvSDMMC_Init();
if( xSDCardStatus == pdPASS )
{
pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) );
if( pxDisk != NULL )
{
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
if( xPlusFATMutex == NULL)
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
pxDisk->ulNumberOfSectors = xCardInfo->card_blknr;
pxDisk->ulSignature = sdSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.ulMemorySize = sdIOMAN_MEM_SIZE;
xParameters.ulSectorSize = 512;
xParameters.fnWriteBlocks = prvFFWrite;
xParameters.fnReadBlocks = prvFFRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be
protected with the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in
the +FAT driver, and also to avoid concurrent calls to
prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_SDDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xFFError ) );
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_SDDiskMount( pxDisk ) == 0 )
{
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if ( PartitionAndFormatEmmcDisk(pxDisk) != FF_ERR_NONE )
{
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card/emmc fail.\n");
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskInit: Mount SD-card/emmc as root \"%s\"\n", pcName );
}
#else
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card/emmc fail.\n");
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
#endif
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card as root \"%s\"\n", pcName );
}
} /* if( pxDisk->pxIOManager != NULL ) */
} /* if( xPlusFATMutex != NULL) */
} /* if( pxDisk != NULL ) */
else
{
FF_PRINTF( "FF_SDDiskInit: Malloc failed\n" );
}
} /* if( xSDCardStatus == pdPASS ) */
else
{
FF_PRINTF( "FF_SDDiskInit: prvSDMMC_Init failed\n" );
pxDisk = NULL;
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
/* Format the drive - try FAT32 with large clusters. */
xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_SDDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
}
else
{
FF_PRINTF( "FF_SDDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
xError = FF_SDDiskMount( pxDisk );
FF_PRINTF( "FF_SDDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = pdPASS;
}
}
}
return xReturn;
}
BaseType_t FF_SDDiskFormatRemount( FF_Disk_t *pxDisk, const char *pcName )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_SDDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
#if DEVICE_TYPE_SELECT == EMMC_FLASH
if ( PartitionAndFormatEmmcDisk(pxDisk) != FF_ERR_NONE )
{
FF_PRINTF( "FF_SDDiskFormatRemount: PartitionAndFormatEmmcDisk fail.\n");
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SDDiskFormatRemount: Mount SD-card/emmc as root \"%s\"\n", pcName );
}
#else
FF_PRINTF( "FF_SDDiskInit: Mounted SD-card/emmc fail.\n");
FF_SDDiskDelete( pxDisk );
pxDisk = NULL;
#endif
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */
BaseType_t FF_SDDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SDDiskMount: %08lX\n", xFFError );
xReturn = pdFAIL;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
FF_SDDiskShowPartition( pxDisk );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
FF_IOManager_t *sddisk_ioman( FF_Disk_t *pxDisk )
{
FF_IOManager_t *pxReturn;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
{
pxReturn = pxDisk->pxIOManager;
}
else
{
pxReturn = NULL;
}
return pxReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_SDDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SDDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( sdHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sdSECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sdSECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvSDMMC_Init( void )
{
if (!xCardInfo) {
xCardInfo = mmcsd_get_sdmmc_card_info();
if (!xCardInfo)
return pdFAIL;
}
mmcsd_set_blksize(xCardInfo);
return pdPASS;
}
/*-----------------------------------------------------------*/
#if DEVICE_TYPE_SELECT == EMMC_FLASH
static uint32_t cached_sector = 0xffffffff;
static uint8_t cached_data[emmcSECTOR_SIZE];
int32_t phyRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount)
{
int32_t iReturn;
/*_RB_ Many of the comments in this file apply to other functions in the file. */
iReturn = mmcsd_req_blk( xCardInfo, ulSectorNumber, pucBuffer, ulSectorCount, 0 );
/*_RB_ I'm guessing 512 is a sector size, but that needs to be clear.
Is it defined in a header somewhere? If so we can do a search and
replace in files on it as it seems to be used everywhere. */
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
/*_RB_ Signed number used to return bitmap (again below). */
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
int32_t phyWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount)
{
int32_t iReturn;
xSDCardStatus = prvSDMMC_Init();
iReturn = mmcsd_req_blk( xCardInfo, ulSectorNumber, pucBuffer, ulSectorCount, 1 );
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
return iReturn;
}
#define EMMC_RW_MAX_SIZE 0x100000
static int raw_emmc_read(uint32_t offset, size_t size, uint8_t *data)
{
unsigned int blkcnt = 0;
unsigned int blkstart = 0;
unsigned char *ptembuf = NULL;
unsigned int inoffset = 0;
unsigned int readsize = 0;
int ret = 0;
xSDCardStatus = prvSDMMC_Init();
blkstart = offset / emmcSECTOR_SIZE;
inoffset = offset - blkstart * emmcSECTOR_SIZE;
readsize = size + inoffset;
blkcnt = (readsize + emmcSECTOR_SIZE - 1) / emmcSECTOR_SIZE;
ptembuf = (uint8_t *)pvPortMalloc(blkcnt * emmcSECTOR_SIZE);
if(!ptembuf)
printf("malloc Error!!1\n");
ret = phyRead(ptembuf, blkstart, blkcnt);
memcpy(data, ptembuf + inoffset, size);
if(ptembuf) {
free(ptembuf);
ptembuf = NULL;
}
return ret;
}
static int raw_emmc_write(uint32_t offset, size_t size, uint8_t *data)
{
unsigned int blkcnt = 0;
unsigned int blkstart = 0, blkend = 0;
unsigned char *ptembuf = NULL;
unsigned int inoffset = 0;
unsigned int endoffset = 0;
unsigned int wsize = 0;
int ret = 0;
xSDCardStatus = prvSDMMC_Init();
blkstart = offset / emmcSECTOR_SIZE;
inoffset = offset % emmcSECTOR_SIZE;
wsize = size + inoffset;
blkcnt = (wsize + emmcSECTOR_SIZE - 1) / emmcSECTOR_SIZE;
blkend = blkstart + blkcnt - 1;
endoffset = wsize % emmcSECTOR_SIZE;
ptembuf = (uint8_t *)pvPortMalloc(blkcnt * emmcSECTOR_SIZE);
if(ptembuf) {
if (inoffset) {
if (blkstart != cached_sector) {
phyRead(cached_data, blkstart, 1);
cached_sector = blkstart;
}
memcpy(ptembuf, cached_data, inoffset);
}
if (data)
memcpy(ptembuf + inoffset, data, size);
else
memset(ptembuf + inoffset, 0xff, size);
if (cached_sector == blkstart) {
if (size > emmcSECTOR_SIZE - inoffset)
memcpy(cached_data + inoffset, ptembuf + inoffset, emmcSECTOR_SIZE - inoffset);
else
memcpy(cached_data + inoffset, ptembuf + inoffset, size);
}
if (endoffset) {
if (blkend != cached_sector) {
phyRead(cached_data, blkend, 1);
cached_sector = blkend;
}
memcpy(ptembuf + wsize, cached_data + endoffset, emmcSECTOR_SIZE - endoffset);
memcpy(cached_data, ptembuf + wsize - endoffset, endoffset);
}
ret = phyWrite(ptembuf,blkstart,blkcnt);
if(ptembuf) {
free(ptembuf);
ptembuf = NULL;
}
} else
printf("emmc_write malloc Error!!1\n");
return ret;
}
int emmc_read(uint32_t offset, size_t size, uint8_t *data)
{
int32_t leftsize = size;
int32_t off = offset;
uint8_t *buf = data;
uint32_t rsize;
int ret;
while (leftsize > 0) {
rsize = leftsize > EMMC_RW_MAX_SIZE ? EMMC_RW_MAX_SIZE : leftsize;
ret = raw_emmc_read(off, rsize, buf);
if (ret)
return ret;
leftsize -= rsize;
off += rsize;
buf += rsize;
}
return 0;
}
int emmc_write(uint32_t offset, size_t size, uint8_t *data)
{
int32_t leftsize = size;
int32_t off = offset;
uint8_t *buf = data;
uint32_t wsize;
int ret;
while (leftsize > 0) {
wsize = leftsize > EMMC_RW_MAX_SIZE ? EMMC_RW_MAX_SIZE : leftsize;
ret = raw_emmc_write(off, wsize, buf);
if (ret)
return ret;
leftsize -= wsize;
off += wsize;
if (buf)
buf += wsize;
}
return 0;
}
#endif

View File

@ -0,0 +1,451 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* 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.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* LPC18xx includes. */
#include "chip.h"
#include "board.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_sfdisk.h"
#include "ff_sys.h"
#include "sfud.h"
/* Misc definitions. */
#define sfSIGNATURE 0x41404342UL
#define sfHUNDRED_64_BIT ( 100ull )
#define sfBYTES_PER_MB ( 1024ull * 1024ull )
#define sfSECTOR_SIZE ( 4096ull )
#define sfSECTORS_PER_MB ( sfBYTES_PER_MB / sfSECTOR_SIZE )
#define sfIOMAN_MEM_SIZE 16384
#define sfDISK_MEDIA_OFFSET OTA_MEDIA_OFFSET
#define sfAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 )
/*-----------------------------------------------------------*/
/*_RB_ Functions require comment blocks. */
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
/*-----------------------------------------------------------*/
/*_RB_ Variables require a comment block where appropriate. */
static sfud_flash *sflash;
static SemaphoreHandle_t xPlusFATMutex;
/*-----------------------------------------------------------*/
static int32_t prvFFRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
/*_RB_ Many of the comments in this file apply to other functions in the file. */
if( ( pxDisk != NULL ) &&
( sflash != NULL ) &&
( pxDisk->ulSignature == sfSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
iReturn = sfud_read(sflash, sfDISK_MEDIA_OFFSET + ulSectorNumber * sfSECTOR_SIZE,
ulSectorCount * sfSECTOR_SIZE, pucBuffer);
/*_RB_ I'm guessing 4096 is a sector size, but that needs to be clear.
Is it defined in a header somewhere? If so we can do a search and
replace in files on it as it seems to be used everywhere. */
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
/*_RB_ Signed number used to return bitmap (again below). */
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised != 0 )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvFFWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
if( ( pxDisk != NULL ) &&
( sflash != NULL ) &&
( pxDisk->ulSignature == sfSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
iReturn = sfud_erase_write(sflash, sfDISK_MEDIA_OFFSET + ulSectorNumber * sfSECTOR_SIZE,
ulSectorCount * sfSECTOR_SIZE, pucBuffer);
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised )
{
FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
void FF_SFDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
#define sfHIDDEN_SECTOR_COUNT 8
#define sfPRIMARY_PARTITIONS 1
#define sfPARTITION_NUMBER 0 /* Only a single partition is used. */
static FF_Error_t PartitionAndFormatSFDisk( FF_Disk_t * pxDisk )
{
FF_PartitionParameters_t xPartition;
FF_Error_t xError;
/* Create a single partition that fills all available space on the disk. */
memset( &xPartition, '\0', sizeof( xPartition ) );
xPartition.ulSectorCount = OTA_MEDIA_SIZE / sfSECTOR_SIZE;
xPartition.ulHiddenSectors = sfHIDDEN_SECTOR_COUNT;
xPartition.xPrimaryCount = sfPRIMARY_PARTITIONS;
xPartition.eSizeType = eSizeIsQuota;
/* Partition the disk */
xError = FF_Partition( pxDisk, &xPartition );
FF_PRINTF( "FF_Partition: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
if( FF_isERR( xError ) == pdFALSE )
{
/* Format the partition. */
xError = FF_Format( pxDisk, sfPARTITION_NUMBER, pdFALSE, pdFALSE );
FF_PRINTF( "FF_Format: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
if ( FF_isERR( xError ) == pdFALSE )
{
xError = FF_Mount( pxDisk, 0 );
FF_PRINTF( "FF_Mount: %s\n", ( const char * ) FF_GetErrMessage( xError ) );
FF_SFDiskShowPartition( pxDisk );
}
}
return xError;
}
/* mount an spi-flash partition */
FF_Disk_t *FF_SFDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t * pxDisk;
sflash = sfud_get_device(0);
if( sflash != NULL )
{
pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) );
if( pxDisk != NULL )
{
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
if( xPlusFATMutex == NULL)
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
//pxDisk->ulNumberOfSectors = sflash->chip.capacity / sfSECTOR_SIZE;
pxDisk->ulNumberOfSectors = OTA_MEDIA_SIZE / sfSECTOR_SIZE;
pxDisk->ulSignature = sfSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.ulMemorySize = sfIOMAN_MEM_SIZE;
xParameters.ulSectorSize = sfSECTOR_SIZE;
xParameters.fnWriteBlocks = prvFFWrite;
xParameters.fnReadBlocks = prvFFRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be
protected with the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in
the +FAT driver, and also to avoid concurrent calls to
prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_SFDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xFFError ) );
FF_SFDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_SFDiskMount( pxDisk ) == 0 )
{
if ( PartitionAndFormatSFDisk(pxDisk) != FF_ERR_NONE )
{
FF_PRINTF( "FF_SFDiskInit: Mount spi-flash fail.\n");
FF_SFDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SFDiskInit: Mounted spi-flash as root \"%s\"\n", pcName );
}
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_SFDiskInit: Mounted spi-flash as root \"%s\"\n", pcName );
}
} /* if( pxDisk->pxIOManager != NULL ) */
} /* if( xPlusFATMutex != NULL) */
} /* if( pxDisk != NULL ) */
else
{
FF_PRINTF( "FF_SFDiskInit: Malloc failed\n" );
}
} /* if( sflash != NULL ) */
else
{
FF_PRINTF( "FF_SFDiskInit: sfud_get_device failed\n" );
pxDisk = NULL;
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SFDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_SFDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
/* Format the drive - try FAT32 with large clusters. */
xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_SFDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
}
else
{
FF_PRINTF( "FF_SFDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
xError = FF_SFDiskMount( pxDisk );
FF_PRINTF( "FF_SFDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = pdPASS;
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */
BaseType_t FF_SFDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_SFDiskMount: %08lX\n", xFFError );
xReturn = pdFAIL;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
FF_SFDiskShowPartition( pxDisk );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_SFDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_SFDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( sfHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / sfSECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / sfSECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,424 @@
/*
* FreeRTOS+FAT build 191128 - Note: FreeRTOS+FAT is still in the lab!
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Authors include James Walmsley, Hein Tibosch and Richard Barry
*
* 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.
*
* https://www.FreeRTOS.org
*
*/
/* Standard includes. */
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
/* LPC18xx includes. */
#include "chip.h"
#include "board.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "portmacro.h"
/* FreeRTOS+FAT includes. */
#include "ff_usbdisk.h"
#include "usb_massstorage.h"
#include "ff_sys.h"
/* Misc definitions. */
#define usbSIGNATURE 0x41404342UL
#define usbHUNDRED_64_BIT ( 100ull )
#define usbBYTES_PER_MB ( 1024ull * 1024ull )
#define usbSECTORS_PER_MB ( usbBYTES_PER_MB / 512ull )
#define usbIOMAN_MEM_SIZE 4096
#define usbAligned( pvAddress ) ( ( ( ( size_t ) ( pvAddress ) ) & ( sizeof( size_t ) - 1 ) ) == 0 )
/*-----------------------------------------------------------*/
/*_RB_ Functions require comment blocks. */
static int32_t prvUSBDisk_Init( void );
static int32_t prvFFUSBDiskRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
static int32_t prvFFUSBDiskWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk );
/*-----------------------------------------------------------*/
/*_RB_ Variables require a comment block where appropriate. */
static struct blk_desc *xUSBInfo;
static BaseType_t xUSBDiskStatus;
static SemaphoreHandle_t xPlusFATMutex;
/*-----------------------------------------------------------*/
static int32_t prvFFUSBDiskRead( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
/*_RB_ Many of the comments in this file apply to other functions in the file. */
if( ( pxDisk != NULL ) && NULL != xUSBInfo->block_read &&
( xUSBDiskStatus == pdPASS ) &&
( pxDisk->ulSignature == usbSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
iReturn = xUSBInfo->block_read(xUSBInfo, ulSectorNumber, ulSectorCount, (void *)pucBuffer);
/*_RB_ I'm guessing 512 is a sector size, but that needs to be clear.
Is it defined in a header somewhere? If so we can do a search and
replace in files on it as it seems to be used everywhere. */
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
/*_RB_ Signed number used to return bitmap (again below). */
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised != 0 )
{
FF_PRINTF( "prvFFRead: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_READ | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvFFUSBDiskWrite( uint8_t *pucBuffer, uint32_t ulSectorNumber, uint32_t ulSectorCount, FF_Disk_t *pxDisk )
{
int32_t iReturn;
if( ( pxDisk != NULL ) && NULL != xUSBInfo->block_write &&
( xUSBDiskStatus == pdPASS ) &&
( pxDisk->ulSignature == usbSIGNATURE ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( ulSectorNumber < pxDisk->ulNumberOfSectors ) &&
( ( pxDisk->ulNumberOfSectors - ulSectorNumber ) >= ulSectorCount ) )
{
iReturn = xUSBInfo->block_write(xUSBInfo, ulSectorNumber, ulSectorCount, (const void *)pucBuffer);
if( iReturn == 0 ) /*_RB_ Signed/unsigned mismatch (twice!) */
{
iReturn = FF_ERR_NONE;
}
else
{
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
}
else
{
memset( ( void * ) pucBuffer, '\0', ulSectorCount * 512 );
if( pxDisk->xStatus.bIsInitialised )
{
FF_PRINTF( "prvFFWrite: warning: %lu + %lu > %lu\n", ulSectorNumber, ulSectorCount, pxDisk->ulNumberOfSectors );
}
iReturn = ( FF_ERR_IOMAN_OUT_OF_BOUNDS_WRITE | FF_ERRFLAG );
}
return iReturn;
}
/*-----------------------------------------------------------*/
void FF_USBDiskFlush( FF_Disk_t *pxDisk )
{
if( ( pxDisk != NULL ) &&
( pxDisk->xStatus.bIsInitialised != pdFALSE ) &&
( pxDisk->pxIOManager != NULL ) )
{
FF_FlushCache( pxDisk->pxIOManager );
}
}
/*-----------------------------------------------------------*/
/* Initialise the USB driver and mount an Udisk */
FF_Disk_t *FF_USBDiskInit( const char *pcName )
{
FF_Error_t xFFError;
BaseType_t xPartitionNumber = 0;
FF_CreationParameters_t xParameters;
FF_Disk_t * pxDisk;
xUSBDiskStatus = prvUSBDisk_Init();
if( xUSBDiskStatus == pdPASS )
{
pxDisk = ( FF_Disk_t * ) pvPortMalloc( sizeof( *pxDisk ) );
if( pxDisk != NULL )
{
/* Initialise the created disk structure. */
memset( pxDisk, '\0', sizeof( *pxDisk ) );
if( xPlusFATMutex == NULL)
{
xPlusFATMutex = xSemaphoreCreateRecursiveMutex();
}
pxDisk->ulNumberOfSectors = xUSBInfo->lba;
pxDisk->ulSignature = usbSIGNATURE;
if( xPlusFATMutex != NULL)
{
memset( &xParameters, '\0', sizeof( xParameters ) );
xParameters.ulMemorySize = usbIOMAN_MEM_SIZE;
xParameters.ulSectorSize = 512;
xParameters.fnWriteBlocks = prvFFUSBDiskWrite;
xParameters.fnReadBlocks = prvFFUSBDiskRead;
xParameters.pxDisk = pxDisk;
/* prvFFRead()/prvFFWrite() are not re-entrant and must be
protected with the use of a semaphore. */
xParameters.xBlockDeviceIsReentrant = pdFALSE;
/* The semaphore will be used to protect critical sections in
the +FAT driver, and also to avoid concurrent calls to
prvFFRead()/prvFFWrite() from different tasks. */
xParameters.pvSemaphore = ( void * ) xPlusFATMutex;
pxDisk->pxIOManager = FF_CreateIOManger( &xParameters, &xFFError );
if( pxDisk->pxIOManager == NULL )
{
FF_PRINTF( "FF_USBDiskInit: FF_CreateIOManger: %s\n", ( const char * ) FF_GetErrMessage( xFFError ) );
FF_USBDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
pxDisk->xStatus.bIsInitialised = pdTRUE;
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
if( FF_USBDiskMount( pxDisk ) == 0 )
{
FF_USBDiskDelete( pxDisk );
pxDisk = NULL;
}
else
{
if( pcName == NULL )
{
pcName = "/";
}
FF_FS_Add( pcName, pxDisk );
FF_PRINTF( "FF_USBDiskInit: Mounted Udisk as root \"%s\"\n", pcName );
FF_USBDiskShowPartition( pxDisk );
}
} /* if( pxDisk->pxIOManager != NULL ) */
} /* if( xPlusFATMutex != NULL) */
} /* if( pxDisk != NULL ) */
else
{
FF_PRINTF( "FF_USBDiskInit: Malloc failed\n" );
}
} /* if( xUSBDiskStatus == pdPASS ) */
else
{
FF_PRINTF( "FF_USBDiskInit: prvUSBDisk_Init failed\n" );
pxDisk = NULL;
}
return pxDisk;
}
/*-----------------------------------------------------------*/
BaseType_t FF_USBDiskFormat( FF_Disk_t *pxDisk, BaseType_t xPartitionNumber )
{
FF_Error_t xError;
BaseType_t xReturn = pdFAIL;
xError = FF_Unmount( pxDisk );
if( FF_isERR( xError ) != pdFALSE )
{
FF_PRINTF( "FF_USBDiskFormat: unmount fails: %08x\n", ( unsigned ) xError );
}
else
{
/* Format the drive - try FAT32 with large clusters. */
xError = FF_Format( pxDisk, xPartitionNumber, pdFALSE, pdFALSE);
if( FF_isERR( xError ) )
{
FF_PRINTF( "FF_USBDiskFormat: %s\n", (const char*)FF_GetErrMessage( xError ) );
}
else
{
FF_PRINTF( "FF_USBDiskFormat: OK, now remounting\n" );
pxDisk->xStatus.bPartitionNumber = xPartitionNumber;
xError = FF_USBDiskMount( pxDisk );
FF_PRINTF( "FF_USBDiskFormat: rc %08x\n", ( unsigned )xError );
if( FF_isERR( xError ) == pdFALSE )
{
xReturn = pdPASS;
}
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Get a pointer to IOMAN, which can be used for all FreeRTOS+FAT functions */
BaseType_t FF_USBDiskMount( FF_Disk_t *pxDisk )
{
FF_Error_t xFFError;
BaseType_t xReturn;
/* Mount the partition */
xFFError = FF_Mount( pxDisk, pxDisk->xStatus.bPartitionNumber );
if( FF_isERR( xFFError ) )
{
FF_PRINTF( "FF_USBDiskMount: %08lX\n", xFFError );
xReturn = pdFAIL;
}
else
{
pxDisk->xStatus.bIsMounted = pdTRUE;
FF_PRINTF( "****** FreeRTOS+FAT initialized %lu sectors\n", pxDisk->pxIOManager->xPartition.ulTotalSectors );
FF_USBDiskShowPartition( pxDisk );
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
FF_IOManager_t *usbdisk_ioman( FF_Disk_t *pxDisk )
{
FF_IOManager_t *pxReturn;
if( ( pxDisk != NULL ) && ( pxDisk->xStatus.bIsInitialised != pdFALSE ) )
{
pxReturn = pxDisk->pxIOManager;
}
else
{
pxReturn = NULL;
}
return pxReturn;
}
/*-----------------------------------------------------------*/
/* Release all resources */
BaseType_t FF_USBDiskDelete( FF_Disk_t *pxDisk )
{
if( pxDisk != NULL )
{
pxDisk->ulSignature = 0;
pxDisk->xStatus.bIsInitialised = 0;
if( pxDisk->pxIOManager != NULL )
{
if( FF_Mounted( pxDisk->pxIOManager ) != pdFALSE )
{
FF_Unmount( pxDisk );
}
FF_DeleteIOManager( pxDisk->pxIOManager );
}
vPortFree( pxDisk );
}
return 1;
}
/*-----------------------------------------------------------*/
BaseType_t FF_USBDiskShowPartition( FF_Disk_t *pxDisk )
{
FF_Error_t xError;
uint64_t ullFreeSectors;
uint32_t ulTotalSizeMB, ulFreeSizeMB;
int iPercentageFree;
FF_IOManager_t *pxIOManager;
const char *pcTypeName = "unknown type";
BaseType_t xReturn = pdPASS;
if( pxDisk == NULL )
{
xReturn = pdFAIL;
}
else
{
pxIOManager = pxDisk->pxIOManager;
FF_PRINTF( "Reading FAT and calculating Free Space\n" );
switch( pxIOManager->xPartition.ucType )
{
case FF_T_FAT12:
pcTypeName = "FAT12";
break;
case FF_T_FAT16:
pcTypeName = "FAT16";
break;
case FF_T_FAT32:
pcTypeName = "FAT32";
break;
default:
pcTypeName = "UNKOWN";
break;
}
FF_GetFreeSize( pxIOManager, &xError );
ullFreeSectors = pxIOManager->xPartition.ulFreeClusterCount * pxIOManager->xPartition.ulSectorsPerCluster;
iPercentageFree = ( int ) ( ( usbHUNDRED_64_BIT * ullFreeSectors + pxIOManager->xPartition.ulDataSectors / 2 ) /
( ( uint64_t )pxIOManager->xPartition.ulDataSectors ) );
ulTotalSizeMB = pxIOManager->xPartition.ulDataSectors / usbSECTORS_PER_MB;
ulFreeSizeMB = ( uint32_t ) ( ullFreeSectors / usbSECTORS_PER_MB );
/* It is better not to use the 64-bit format such as %Lu because it
might not be implemented. */
FF_PRINTF( "Partition Nr %8u\n", pxDisk->xStatus.bPartitionNumber );
FF_PRINTF( "Type %8u (%s)\n", pxIOManager->xPartition.ucType, pcTypeName );
FF_PRINTF( "VolLabel '%8s' \n", pxIOManager->xPartition.pcVolumeLabel );
FF_PRINTF( "TotalSectors %8lu\n", pxIOManager->xPartition.ulTotalSectors );
FF_PRINTF( "SecsPerCluster %8lu\n", pxIOManager->xPartition.ulSectorsPerCluster );
FF_PRINTF( "Size %8lu MB\n", ulTotalSizeMB );
FF_PRINTF( "FreeSize %8lu MB ( %d perc free )\n", ulFreeSizeMB, iPercentageFree );
}
return xReturn;
}
/*-----------------------------------------------------------*/
static int32_t prvUSBDisk_Init( void )
{
xUSBInfo = &usb_dev_desc[0];//use the first device
return pdPASS;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,355 @@
/*
* FreeRTOS+CLI V1.0.4
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/* Standard includes. */
#include <string.h>
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
/* Utils includes. */
#include "FreeRTOS_CLI.h"
/* If the application writer needs to place the buffer used by the CLI at a
fixed address then set configAPPLICATION_PROVIDES_cOutputBuffer to 1 in
FreeRTOSConfig.h, then declare an array with the following name and size in
one of the application files:
char cOutputBuffer[ configCOMMAND_INT_MAX_OUTPUT_SIZE ];
*/
#ifndef configAPPLICATION_PROVIDES_cOutputBuffer
#define configAPPLICATION_PROVIDES_cOutputBuffer 0
#endif
typedef struct xCOMMAND_INPUT_LIST
{
const CLI_Command_Definition_t *pxCommandLineDefinition;
struct xCOMMAND_INPUT_LIST *pxNext;
} CLI_Definition_List_Item_t;
/*
* The callback function that is executed when "help" is entered. This is the
* only default command that is always present.
*/
static BaseType_t prvHelpCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
/*
* Return the number of parameters that follow the command name.
*/
static int8_t prvGetNumberOfParameters( const char *pcCommandString );
/* The definition of the "help" command. This command is always at the front
of the list of registered commands. */
static const CLI_Command_Definition_t xHelpCommand =
{
"help",
"\r\nhelp:\r\n Lists all the registered commands\r\n\r\n",
prvHelpCommand,
0
};
/* The definition of the list of commands. Commands that are registered are
added to this list. */
static CLI_Definition_List_Item_t xRegisteredCommands =
{
&xHelpCommand, /* The first command in the list is always the help command, defined in this file. */
NULL /* The next pointer is initialised to NULL, as there are no other registered commands yet. */
};
/* A buffer into which command outputs can be written is declared here, rather
than in the command console implementation, to allow multiple command consoles
to share the same buffer. For example, an application may allow access to the
command interpreter by UART and by Ethernet. Sharing a buffer is done purely
to save RAM. Note, however, that the command console itself is not re-entrant,
so only one command interpreter interface can be used at any one time. For that
reason, no attempt at providing mutual exclusion to the cOutputBuffer array is
attempted.
configAPPLICATION_PROVIDES_cOutputBuffer is provided to allow the application
writer to provide their own cOutputBuffer declaration in cases where the
buffer needs to be placed at a fixed address (rather than by the linker). */
#if( configAPPLICATION_PROVIDES_cOutputBuffer == 0 )
static char cOutputBuffer[ configCOMMAND_INT_MAX_OUTPUT_SIZE ];
#else
extern char cOutputBuffer[ configCOMMAND_INT_MAX_OUTPUT_SIZE ];
#endif
/*-----------------------------------------------------------*/
BaseType_t FreeRTOS_CLIRegisterCommand( const CLI_Command_Definition_t * const pxCommandToRegister )
{
static CLI_Definition_List_Item_t *pxLastCommandInList = &xRegisteredCommands;
CLI_Definition_List_Item_t *pxNewListItem;
BaseType_t xReturn = pdFAIL;
/* Check the parameter is not NULL. */
configASSERT( pxCommandToRegister );
/* Create a new list item that will reference the command being registered. */
pxNewListItem = ( CLI_Definition_List_Item_t * ) pvPortMalloc( sizeof( CLI_Definition_List_Item_t ) );
configASSERT( pxNewListItem );
if( pxNewListItem != NULL )
{
taskENTER_CRITICAL();
{
/* Reference the command being registered from the newly created
list item. */
pxNewListItem->pxCommandLineDefinition = pxCommandToRegister;
/* The new list item will get added to the end of the list, so
pxNext has nowhere to point. */
pxNewListItem->pxNext = NULL;
/* Add the newly created list item to the end of the already existing
list. */
pxLastCommandInList->pxNext = pxNewListItem;
/* Set the end of list marker to the new list item. */
pxLastCommandInList = pxNewListItem;
}
taskEXIT_CRITICAL();
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
BaseType_t FreeRTOS_CLIProcessCommand( const char * const pcCommandInput, char * pcWriteBuffer, size_t xWriteBufferLen )
{
static const CLI_Definition_List_Item_t *pxCommand = NULL;
BaseType_t xReturn = pdTRUE;
const char *pcRegisteredCommandString;
size_t xCommandStringLength;
/* Note: This function is not re-entrant. It must not be called from more
thank one task. */
if( pxCommand == NULL )
{
/* Search for the command string in the list of registered commands. */
for( pxCommand = &xRegisteredCommands; pxCommand != NULL; pxCommand = pxCommand->pxNext )
{
pcRegisteredCommandString = pxCommand->pxCommandLineDefinition->pcCommand;
xCommandStringLength = strlen( pcRegisteredCommandString );
/* To ensure the string lengths match exactly, so as not to pick up
a sub-string of a longer command, check the byte after the expected
end of the string is either the end of the string or a space before
a parameter. */
if( strncmp( pcCommandInput, pcRegisteredCommandString, xCommandStringLength ) == 0 )
{
if( ( pcCommandInput[ xCommandStringLength ] == ' ' ) || ( pcCommandInput[ xCommandStringLength ] == 0x00 ) )
{
/* The command has been found. Check it has the expected
number of parameters. If cExpectedNumberOfParameters is -1,
then there could be a variable number of parameters and no
check is made. */
if( pxCommand->pxCommandLineDefinition->cExpectedNumberOfParameters >= 0 )
{
if( prvGetNumberOfParameters( pcCommandInput ) != pxCommand->pxCommandLineDefinition->cExpectedNumberOfParameters )
{
xReturn = pdFALSE;
}
if (pxCommand->pxCommandLineDefinition->cExpectedNumberOfParameters == 0) {
xReturn = pdTRUE;
}
}
break;
}
}
}
}
if( ( pxCommand != NULL ) && ( xReturn == pdFALSE ) )
{
/* The command was found, but the number of parameters with the command
was incorrect. */
strncpy( pcWriteBuffer, "Incorrect command parameter(s). Enter \"help\" to view a list of available commands.\r\n\r\n", xWriteBufferLen );
pxCommand = NULL;
}
else if( pxCommand != NULL )
{
/* Call the callback function that is registered to this command. */
xReturn = pxCommand->pxCommandLineDefinition->pxCommandInterpreter( pcWriteBuffer, xWriteBufferLen, pcCommandInput );
/* If xReturn is pdFALSE, then no further strings will be returned
after this one, and pxCommand can be reset to NULL ready to search
for the next entered command. */
if( xReturn == pdFALSE )
{
pxCommand = NULL;
}
}
else
{
/* pxCommand was NULL, the command was not found. */
strncpy( pcWriteBuffer, "Command not recognised. Enter 'help' to view a list of available commands.\r\n\r\n", xWriteBufferLen );
xReturn = pdFALSE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
char *FreeRTOS_CLIGetOutputBuffer( void )
{
return cOutputBuffer;
}
/*-----------------------------------------------------------*/
const char *FreeRTOS_CLIGetParameter( const char *pcCommandString, UBaseType_t uxWantedParameter, BaseType_t *pxParameterStringLength )
{
UBaseType_t uxParametersFound = 0;
const char *pcReturn = NULL;
*pxParameterStringLength = 0;
while( uxParametersFound < uxWantedParameter )
{
/* Index the character pointer past the current word. If this is the start
of the command string then the first word is the command itself. */
while( ( ( *pcCommandString ) != 0x00 ) && ( ( *pcCommandString ) != ' ' ) )
{
pcCommandString++;
}
/* Find the start of the next string. */
while( ( ( *pcCommandString ) != 0x00 ) && ( ( *pcCommandString ) == ' ' ) )
{
pcCommandString++;
}
/* Was a string found? */
if( *pcCommandString != 0x00 )
{
/* Is this the start of the required parameter? */
uxParametersFound++;
if( uxParametersFound == uxWantedParameter )
{
/* How long is the parameter? */
pcReturn = pcCommandString;
while( ( ( *pcCommandString ) != 0x00 ) && ( ( *pcCommandString ) != ' ' ) )
{
( *pxParameterStringLength )++;
pcCommandString++;
}
if( *pxParameterStringLength == 0 )
{
pcReturn = NULL;
}
break;
}
}
else
{
break;
}
}
return pcReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvHelpCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
static const CLI_Definition_List_Item_t * pxCommand = NULL;
BaseType_t xReturn;
( void ) pcCommandString;
if( pxCommand == NULL )
{
/* Reset the pxCommand pointer back to the start of the list. */
pxCommand = &xRegisteredCommands;
}
/* Return the next command help string, before moving the pointer on to
the next command in the list. */
strncpy( pcWriteBuffer, pxCommand->pxCommandLineDefinition->pcHelpString, xWriteBufferLen );
pxCommand = pxCommand->pxNext;
if( pxCommand == NULL )
{
/* There are no more commands in the list, so there will be no more
strings to return after this one and pdFALSE should be returned. */
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
return xReturn;
}
/*-----------------------------------------------------------*/
static int8_t prvGetNumberOfParameters( const char *pcCommandString )
{
int8_t cParameters = 0;
BaseType_t xLastCharacterWasSpace = pdFALSE;
/* Count the number of space delimited words in pcCommandString. */
while( *pcCommandString != 0x00 )
{
if( ( *pcCommandString ) == ' ' )
{
if( xLastCharacterWasSpace != pdTRUE )
{
cParameters++;
xLastCharacterWasSpace = pdTRUE;
}
}
else
{
xLastCharacterWasSpace = pdFALSE;
}
pcCommandString++;
}
/* If the command string ended with spaces, then there will have been too
many parameters counted. */
if( xLastCharacterWasSpace == pdTRUE )
{
cParameters--;
}
/* The value returned is one less than the number of space delimited words,
as the first word should be the command itself. */
return cParameters;
}

View File

@ -0,0 +1,105 @@
/*
* FreeRTOS+CLI V1.0.4
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef COMMAND_INTERPRETER_H
#define COMMAND_INTERPRETER_H
/* The prototype to which callback functions used to process command line
commands must comply. pcWriteBuffer is a buffer into which the output from
executing the command can be written, xWriteBufferLen is the length, in bytes of
the pcWriteBuffer buffer, and pcCommandString is the entire string as input by
the user (from which parameters can be extracted).*/
typedef BaseType_t (*pdCOMMAND_LINE_CALLBACK)( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
/* The structure that defines command line commands. A command line command
should be defined by declaring a const structure of this type. */
typedef struct xCOMMAND_LINE_INPUT
{
const char * const pcCommand; /* The command that causes pxCommandInterpreter to be executed. For example "help". Must be all lower case. */
const char * const pcHelpString; /* String that describes how to use the command. Should start with the command itself, and end with "\r\n". For example "help: Returns a list of all the commands\r\n". */
const pdCOMMAND_LINE_CALLBACK pxCommandInterpreter; /* A pointer to the callback function that will return the output generated by the command. */
int8_t cExpectedNumberOfParameters; /* Commands expect a fixed number of parameters, which may be zero. */
} CLI_Command_Definition_t;
/* For backward compatibility. */
#define xCommandLineInput CLI_Command_Definition_t
/*
* Register the command passed in using the pxCommandToRegister parameter.
* Registering a command adds the command to the list of commands that are
* handled by the command interpreter. Once a command has been registered it
* can be executed from the command line.
*/
BaseType_t FreeRTOS_CLIRegisterCommand( const CLI_Command_Definition_t * const pxCommandToRegister );
/*
* Runs the command interpreter for the command string "pcCommandInput". Any
* output generated by running the command will be placed into pcWriteBuffer.
* xWriteBufferLen must indicate the size, in bytes, of the buffer pointed to
* by pcWriteBuffer.
*
* FreeRTOS_CLIProcessCommand should be called repeatedly until it returns pdFALSE.
*
* pcCmdIntProcessCommand is not reentrant. It must not be called from more
* than one task - or at least - by more than one task at a time.
*/
BaseType_t FreeRTOS_CLIProcessCommand( const char * const pcCommandInput, char * pcWriteBuffer, size_t xWriteBufferLen );
/*-----------------------------------------------------------*/
/*
* A buffer into which command outputs can be written is declared in the
* main command interpreter, rather than in the command console implementation,
* to allow application that provide access to the command console via multiple
* interfaces to share a buffer, and therefore save RAM. Note, however, that
* the command interpreter itself is not re-entrant, so only one command
* console interface can be used at any one time. For that reason, no attempt
* is made to provide any mutual exclusion mechanism on the output buffer.
*
* FreeRTOS_CLIGetOutputBuffer() returns the address of the output buffer.
*/
char *FreeRTOS_CLIGetOutputBuffer( void );
/*
* Return a pointer to the xParameterNumber'th word in pcCommandString.
*/
const char *FreeRTOS_CLIGetParameter( const char *pcCommandString, UBaseType_t uxWantedParameter, BaseType_t *pxParameterStringLength );
#endif /* COMMAND_INTERPRETER_H */

View File

@ -0,0 +1,785 @@
/*
* FreeRTOS V202104.00
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/******************************************************************************
*
* http://www.FreeRTOS.org/cli
*
******************************************************************************/
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* FreeRTOS+CLI includes. */
#include "FreeRTOS_CLI.h"
#include "board.h"
#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS
#define configINCLUDE_TRACE_RELATED_CLI_COMMANDS 0
#endif
#ifndef configINCLUDE_QUERY_HEAP_COMMAND
#define configINCLUDE_QUERY_HEAP_COMMAND 0
#endif
/*
* The function that registers the commands that are defined within this file.
*/
void vRegisterSampleCLICommands( void );
/*
* Implements the task-stats command.
*/
static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
/*
* Implements the run-time-stats command.
*/
#if( configGENERATE_RUN_TIME_STATS == 1 )
static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
#endif /* configGENERATE_RUN_TIME_STATS */
/*
* Implements the echo-three-parameters command.
*/
static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
/*
* Implements the echo-parameters command.
*/
static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
#ifdef WIFI_SUPPORT
static BaseType_t prvParameterStartWifiCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
static BaseType_t prvParameterPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
static BaseType_t prvParameterStartBtcoLogCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
static BaseType_t prvParameterStartIwprivCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
#endif
static BaseType_t prvParameterIperfCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
/*
* Implements the "query heap" command.
*/
#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 )
static BaseType_t prvQueryHeapCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
#endif
/*
* Implements the "trace start" and "trace stop" commands;
*/
#if( configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 )
static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString );
#endif
/* Structure that defines the "task-stats" command line command. This generates
a table that gives information on each task in the system. */
static const CLI_Command_Definition_t xTaskStats =
{
"task-stats", /* The command string to type. */
"\r\ntask-stats:\r\n Displays a table showing the state of each FreeRTOS task\r\n",
prvTaskStatsCommand, /* The function to run. */
0 /* No parameters are expected. */
};
/* Structure that defines the "echo_3_parameters" command line command. This
takes exactly three parameters that the command simply echos back one at a
time. */
static const CLI_Command_Definition_t xThreeParameterEcho =
{
"echo-3-parameters",
"\r\necho-3-parameters <param1> <param2> <param3>:\r\n Expects three parameters, echos each in turn\r\n",
prvThreeParameterEchoCommand, /* The function to run. */
3 /* Three parameters are expected, which can take any value. */
};
/* Structure that defines the "echo_parameters" command line command. This
takes a variable number of parameters that the command simply echos back one at
a time. */
static const CLI_Command_Definition_t xParameterEcho =
{
"echo-parameters",
"\r\necho-parameters <...>:\r\n Take variable number of parameters, echos each in turn\r\n",
prvParameterEchoCommand, /* The function to run. */
-1 /* The user can enter any number of commands. */
};
#if( configGENERATE_RUN_TIME_STATS == 1 )
/* Structure that defines the "run-time-stats" command line command. This
generates a table that shows how much run time each task has */
static const CLI_Command_Definition_t xRunTimeStats =
{
"run-time-stats", /* The command string to type. */
"\r\nrun-time-stats:\r\n Displays a table showing how much processing time each FreeRTOS task has used\r\n",
prvRunTimeStatsCommand, /* The function to run. */
0 /* No parameters are expected. */
};
#endif /* configGENERATE_RUN_TIME_STATS */
#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 )
/* Structure that defines the "query_heap" command line command. */
static const CLI_Command_Definition_t xQueryHeap =
{
"query-heap",
"\r\nquery-heap:\r\n Displays the free heap space, and minimum ever free heap space.\r\n",
prvQueryHeapCommand, /* The function to run. */
0 /* The user can enter any number of commands. */
};
#endif /* configQUERY_HEAP_COMMAND */
#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1
/* Structure that defines the "trace" command line command. This takes a single
parameter, which can be either "start" or "stop". */
static const CLI_Command_Definition_t xStartStopTrace =
{
"trace",
"\r\ntrace [start | stop]:\r\n Starts or stops a trace recording for viewing in FreeRTOS+Trace\r\n",
prvStartStopTraceCommand, /* The function to run. */
1 /* One parameter is expected. Valid values are "start" and "stop". */
};
#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */
#ifdef WIFI_SUPPORT
static const CLI_Command_Definition_t xStartWifi =
{
"startwifi",
"\r\nstartwifi [ap | sta]:\r\n Starts AP or STA in FreeRTOS+Trace\r\n",
prvParameterStartWifiCommand, /* The function to run. */
0 /* One parameter is expected. Valid values are "start" and "stop". */
};
static const CLI_Command_Definition_t xPingCmd =
{
"ping",
"\r\nping [192.168.13.20]:\r\n ping remote device in FreeRTOS+Trace\r\n",
prvParameterPingCommand, /* The function to run. */
1 /* One parameter is expected. Valid values are "start" and "stop". */
};
static const CLI_Command_Definition_t xStartBtCoLog =
{
"startbtcolog",
"\r\nstartbtcolog:\r\n Starts btco log in FreeRTOS+Trace\r\n",
prvParameterStartBtcoLogCommand, /* The function to run. */
0 /* One parameter is expected. Valid values are "start" and "stop". */
};
static const CLI_Command_Definition_t xStartIwprivCmd =
{
"iwpriv",
"\r\niwpriv dbg [flow | rx] :\r\n Starts btco log in FreeRTOS+Trace\r\n",
prvParameterStartIwprivCommand, /* The function to run. */
0
};
#endif
static const CLI_Command_Definition_t xIperfCmd =
{//此iperf只用来做飞易通wifi定频测试
"iperf",
"\r\n iperf [ip] [port]:\r\n Starts iperf client\r\n",
prvParameterIperfCommand, /* The function to run. */
0 /* One parameter is expected. Valid values are "start" and "stop". */
};
/*-----------------------------------------------------------*/
void vRegisterSampleCLICommands( void )
{
/* Register all the command line commands defined immediately above. */
FreeRTOS_CLIRegisterCommand( &xTaskStats );
FreeRTOS_CLIRegisterCommand( &xThreeParameterEcho );
FreeRTOS_CLIRegisterCommand( &xParameterEcho );
#if( configGENERATE_RUN_TIME_STATS == 1 )
{
FreeRTOS_CLIRegisterCommand( &xRunTimeStats );
}
#endif
#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 )
{
FreeRTOS_CLIRegisterCommand( &xQueryHeap );
}
#endif
#if( configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1 )
{
FreeRTOS_CLIRegisterCommand( &xStartStopTrace );
}
#endif
#ifdef WIFI_SUPPORT
FreeRTOS_CLIRegisterCommand( &xStartWifi );
FreeRTOS_CLIRegisterCommand( &xPingCmd );
FreeRTOS_CLIRegisterCommand( &xStartBtCoLog);
FreeRTOS_CLIRegisterCommand( &xStartIwprivCmd);
#endif
FreeRTOS_CLIRegisterCommand( &xIperfCmd);
}
/*-----------------------------------------------------------*/
static BaseType_t prvTaskStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *const pcHeader = " State Priority Stack #\r\n************************************************\r\n";
BaseType_t xSpacePadding;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
/* Generate a table of task stats. */
strcpy( pcWriteBuffer, "Task" );
pcWriteBuffer += strlen( pcWriteBuffer );
/* Minus three for the null terminator and half the number of characters in
"Task" so the column lines up with the centre of the heading. */
configASSERT( configMAX_TASK_NAME_LEN > 3 );
for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ )
{
/* Add a space to align columns after the task's name. */
*pcWriteBuffer = ' ';
pcWriteBuffer++;
/* Ensure always terminated. */
*pcWriteBuffer = 0x00;
}
strcpy( pcWriteBuffer, pcHeader );
vTaskList( pcWriteBuffer + strlen( pcHeader ) );
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
/*-----------------------------------------------------------*/
#if( configINCLUDE_QUERY_HEAP_COMMAND == 1 )
static BaseType_t prvQueryHeapCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
sprintf( pcWriteBuffer, "Current free heap %d bytes, minimum ever free heap %d bytes\r\n", ( int ) xPortGetFreeHeapSize(), ( int ) xPortGetMinimumEverFreeHeapSize() );
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
#endif /* configINCLUDE_QUERY_HEAP */
/*-----------------------------------------------------------*/
#if( configGENERATE_RUN_TIME_STATS == 1 )
static BaseType_t prvRunTimeStatsCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char * const pcHeader = " Abs Time % Time\r\n****************************************\r\n";
BaseType_t xSpacePadding;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
/* Generate a table of task stats. */
strcpy( pcWriteBuffer, "Task" );
pcWriteBuffer += strlen( pcWriteBuffer );
/* Pad the string "task" with however many bytes necessary to make it the
length of a task name. Minus three for the null terminator and half the
number of characters in "Task" so the column lines up with the centre of
the heading. */
for( xSpacePadding = strlen( "Task" ); xSpacePadding < ( configMAX_TASK_NAME_LEN - 3 ); xSpacePadding++ )
{
/* Add a space to align columns after the task's name. */
*pcWriteBuffer = ' ';
pcWriteBuffer++;
/* Ensure always terminated. */
*pcWriteBuffer = 0x00;
}
strcpy( pcWriteBuffer, pcHeader );
vTaskGetRunTimeStats( pcWriteBuffer + strlen( pcHeader ) );
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
#endif /* configGENERATE_RUN_TIME_STATS */
/*-----------------------------------------------------------*/
static BaseType_t prvThreeParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
BaseType_t xParameterStringLength, xReturn;
static UBaseType_t uxParameterNumber = 0;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
if( uxParameterNumber == 0 )
{
/* The first time the function is called after the command has been
entered just a header string is returned. */
sprintf( pcWriteBuffer, "The three parameters were:\r\n" );
/* Next time the function is called the first parameter will be echoed
back. */
uxParameterNumber = 1U;
/* There is more data to be returned as no parameters have been echoed
back yet. */
xReturn = pdPASS;
}
else
{
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
uxParameterNumber, /* Return the next parameter. */
&xParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
configASSERT( pcParameter );
/* Return the parameter string. */
memset( pcWriteBuffer, 0x00, xWriteBufferLen );
sprintf( pcWriteBuffer, "%d: ", ( int ) uxParameterNumber );
strncat( pcWriteBuffer, pcParameter, ( size_t ) xParameterStringLength );
strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) );
/* If this is the last of the three parameters then there are no more
strings to return after this one. */
if( uxParameterNumber == 3U )
{
/* If this is the last of the three parameters then there are no more
strings to return after this one. */
xReturn = pdFALSE;
uxParameterNumber = 0;
}
else
{
/* There are more parameters to return after this one. */
xReturn = pdTRUE;
uxParameterNumber++;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
static BaseType_t prvParameterEchoCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
BaseType_t xParameterStringLength, xReturn;
static UBaseType_t uxParameterNumber = 0;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
if( uxParameterNumber == 0 )
{
/* The first time the function is called after the command has been
entered just a header string is returned. */
sprintf( pcWriteBuffer, "The parameters were:\r\n" );
/* Next time the function is called the first parameter will be echoed
back. */
uxParameterNumber = 1U;
/* There is more data to be returned as no parameters have been echoed
back yet. */
xReturn = pdPASS;
}
else
{
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
uxParameterNumber, /* Return the next parameter. */
&xParameterStringLength /* Store the parameter string length. */
);
if( pcParameter != NULL )
{
/* Return the parameter string. */
memset( pcWriteBuffer, 0x00, xWriteBufferLen );
sprintf( pcWriteBuffer, "%d: ", ( int ) uxParameterNumber );
strncat( pcWriteBuffer, ( char * ) pcParameter, ( size_t ) xParameterStringLength );
strncat( pcWriteBuffer, "\r\n", strlen( "\r\n" ) );
/* There might be more parameters to return after this one. */
xReturn = pdTRUE;
uxParameterNumber++;
}
else
{
/* No more parameters were found. Make sure the write buffer does
not contain a valid string. */
pcWriteBuffer[ 0 ] = 0x00;
/* No more data to return. */
xReturn = pdFALSE;
/* Start over the next time this command is executed. */
uxParameterNumber = 0;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/
#if configINCLUDE_TRACE_RELATED_CLI_COMMANDS == 1
static BaseType_t prvStartStopTraceCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
BaseType_t lParameterStringLength;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
1, /* Return the first parameter. */
&lParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
configASSERT( pcParameter );
/* There are only two valid parameter values. */
if( strncmp( pcParameter, "start", strlen( "start" ) ) == 0 )
{
/* Start or restart the trace. */
vTraceStop();
vTraceClear();
vTraceStart();
sprintf( pcWriteBuffer, "Trace recording (re)started.\r\n" );
}
else if( strncmp( pcParameter, "stop", strlen( "stop" ) ) == 0 )
{
/* End the trace, if one is running. */
vTraceStop();
sprintf( pcWriteBuffer, "Stopping trace recording.\r\n" );
}
else
{
sprintf( pcWriteBuffer, "Valid parameters are 'start' and 'stop'.\r\n" );
}
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
#endif /* configINCLUDE_TRACE_RELATED_CLI_COMMANDS */
#ifdef WIFI_SUPPORT
#include "iot_wifi.h"
static BaseType_t prvParameterStartWifiCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
BaseType_t lParameterStringLength;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
1, /* Return the first parameter. */
&lParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
configASSERT( pcParameter );
/* There are only two valid parameter values. */
if( strncmp( pcParameter, "ap", strlen( "ap" ) ) == 0 )
{
//printf("\r\nstart ap\r\n");
start_ap(36, "ap63011", "88888888", 1);
}
else if( strncmp( pcParameter, "sta", strlen( "sta" ) ) == 0 )
{
int pssid_len = 0, ppwd_len = 0;
char ssid[64] = {0}, passwd[64] = {0};
const char *pssid = FreeRTOS_CLIGetParameter
(
pcCommandString,
2,
(BaseType_t *)&pssid_len
);
memcpy(ssid, pssid, pssid_len);
const char *ppwd = FreeRTOS_CLIGetParameter
(
pcCommandString,
3,
(BaseType_t *)&ppwd_len
);
memcpy(passwd, ppwd, ppwd_len);
//printf("\r\nssid:[%s] len:%d passwd:[%s] ppwd_len:%d\r\n", pssid, pssid_len, ppwd, ppwd_len);
start_sta(ssid, passwd, 1);
}
else
{
printf("\r\ninvalid parameters\r\n");
}
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
static BaseType_t prvParameterPingCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
BaseType_t lParameterStringLength;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
1, /* Return the first parameter. */
&lParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
configASSERT( pcParameter );
start_ping(pcParameter);
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
static BaseType_t prvParameterStartBtcoLogCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
//const char *pcParameter;
//BaseType_t lParameterStringLength;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
#if 0
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
1, /* Return the first parameter. */
&lParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
configASSERT( pcParameter );
#endif
enable_btco_log();
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
void cmd_test(const char* temp_uart_buf);//for wifi iwpriv²âÊÔ
static BaseType_t prvParameterStartIwprivCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
//const char *pcParameter;
//BaseType_t lParameterStringLength;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
#if 0
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
2, /* Return the first parameter. */
&lParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
configASSERT( pcParameter );
#endif
cmd_test(pcCommandString);
sprintf( pcWriteBuffer, "\r\n %s started.\r\n" , pcCommandString);
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}
#endif
#if !USE_LWIP
void start_iperf_client(const char* ip, int port);
#else
#include "ethernet.h"
#include "tcpip.h"
#include "lwip/apps/lwiperf.h"
static void* iperf_client_handle = NULL;
#define lwip_addr_converter( ucOctet0, ucOctet1, ucOctet2, ucOctet3 ) \
( ( ( ( uint32_t ) ( ucOctet3 ) ) << 24UL ) | \
( ( ( uint32_t ) ( ucOctet2 ) ) << 16UL ) | \
( ( ( uint32_t ) ( ucOctet1 ) ) << 8UL ) | \
( ( uint32_t ) ( ucOctet0 ) ) )
static void lwiperf_client_report_cb_impl(void *arg, enum lwiperf_report_type report_type,
const ip_addr_t* local_addr, u16_t local_port, const ip_addr_t* remote_addr, u16_t remote_port,
u32_t bytes_transferred, u32_t ms_duration, u32_t bandwidth_kbitpsec)
{
printf("lwiperf_report_cb_impl bytes:%d %d ms \r\n", bytes_transferred, ms_duration);
}
static void start_iperf_client(const char* ip, short port)
{
/*ip_addr_t remote_addr;
char addr_buf[4] = {0};
sscanf(ip, "%d.%d.%d.%d", (int*)&addr_buf[0], (int*)&addr_buf[1], (int*)&addr_buf[2], (int*)&addr_buf[3]);
remote_addr.addr = lwip_addr_converter(addr_buf[0], addr_buf[1], addr_buf[2], addr_buf[3]);
iperf_client_handle = lwiperf_start_tcp_client(&remote_addr, (u16_t)port, LWIPERF_CLIENT, lwiperf_client_report_cb_impl, NULL);*/
}
#endif
static BaseType_t prvParameterIperfCommand( char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString )
{
const char *pcParameter;
BaseType_t lParameterStringLength;
/* Remove compile time warnings about unused parameters, and check the
write buffer is not NULL. NOTE - for simplicity, this example assumes the
write buffer length is adequate, so does not check for buffer overflows. */
( void ) pcCommandString;
( void ) xWriteBufferLen;
configASSERT( pcWriteBuffer );
/* Obtain the parameter string. */
pcParameter = FreeRTOS_CLIGetParameter
(
pcCommandString, /* The command string itself. */
1, /* Return the first parameter. */
&lParameterStringLength /* Store the parameter string length. */
);
/* Sanity check something was returned. */
//configASSERT( pcParameter );
if( strncmp( pcParameter, "client", strlen( "client" ) ) == 0 )
{
printf("\r\n iperf client test start \r\n");
int addr_str_len = 0, port_str_len = 0;
char addr_str[64] = {0}, port_str[64] = {0};
int port = 0;
const char *paddr_str = FreeRTOS_CLIGetParameter
(
pcCommandString,
2,
(BaseType_t *)&addr_str_len
);
memcpy(addr_str, paddr_str, addr_str_len);
const char *pport_str = FreeRTOS_CLIGetParameter
(
pcCommandString,
3,
(BaseType_t *)&port_str_len
);
memcpy(port_str, pport_str, port_str_len);
port = atoi(port_str);
printf("\r\n addr:[%s] len:%d port str:[%s] port len:%d port:%d\r\n", addr_str, addr_str_len, port_str, port_str_len, port);
start_iperf_client(addr_str, port);
printf("\r\n iperf client test end\r\n");
}
else if( strncmp( pcParameter, "stop", strlen( "stop" ) ) == 0 )
{
#if USE_LWIP
if (iperf_client_handle)
lwiperf_abort(iperf_client_handle);
#endif
}
else
{
printf("\r\ninvalid parameters\r\n");
}
/* There is no more data to return after this single string, so return
pdFALSE. */
return pdFALSE;
}

View File

@ -0,0 +1,226 @@
/*
* FreeRTOS V202104.00
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/*
* NOTE: This file uses a third party USB CDC driver.
*/
/* Standard includes. */
#include "string.h"
#include "stdio.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* Example includes. */
#include "FreeRTOS_CLI.h"
/* Demo application includes. */
#include "serial.h"
/* Dimensions the buffer into which input characters are placed. */
#define cmdMAX_INPUT_SIZE 50
/* Dimentions a buffer to be used by the UART driver, if the UART driver uses a
buffer at all. */
#define cmdQUEUE_LENGTH 25
/* DEL acts as a backspace. */
#define cmdASCII_DEL ( 0x7F )
/* The maximum time to wait for the mutex that guards the UART to become
available. */
#define cmdMAX_MUTEX_WAIT pdMS_TO_TICKS( 300 )
#ifndef configCLI_BAUD_RATE
#define configCLI_BAUD_RATE 115200
#endif
/*-----------------------------------------------------------*/
/*
* The task that implements the command console processing.
*/
static void prvUARTCommandConsoleTask( void *pvParameters );
void vUARTCommandConsoleStart( uint16_t usStackSize, UBaseType_t uxPriority );
/*-----------------------------------------------------------*/
/* Const messages output by the command console. */
static const char * const pcWelcomeMessage = "FreeRTOS command server.\r\nType Help to view a list of registered commands.\r\n\r\n>";
static const char * const pcEndOfOutputMessage = "\r\n[Press ENTER to execute the previous command again]\r\n>";
static const char * const pcNewLine = "\r\n";
/* Used to guard access to the UART in case messages are sent to the UART from
more than one task. */
static SemaphoreHandle_t xTxMutex = NULL;
/* The handle to the UART port, which is not used by all ports. */
static xComPortHandle xPort = 0;
/*-----------------------------------------------------------*/
void vUARTCommandConsoleStart( uint16_t usStackSize, UBaseType_t uxPriority )
{
/* Create the semaphore used to access the UART Tx. */
xTxMutex = xSemaphoreCreateMutex();
configASSERT( xTxMutex );
/* Create that task that handles the console itself. */
xTaskCreate( prvUARTCommandConsoleTask, /* The task that implements the command console. */
"CLI", /* Text name assigned to the task. This is just to assist debugging. The kernel does not use this name itself. */
usStackSize, /* The size of the stack allocated to the task. */
NULL, /* The parameter is not used, so NULL is passed. */
uxPriority, /* The priority allocated to the task. */
NULL ); /* A handle is not required, so just pass NULL. */
}
/*-----------------------------------------------------------*/
static void prvUARTCommandConsoleTask( void *pvParameters )
{
signed char cRxedChar;
uint8_t ucInputIndex = 0;
char *pcOutputString;
static char cInputString[ cmdMAX_INPUT_SIZE ], cLastInputString[ cmdMAX_INPUT_SIZE ];
BaseType_t xReturned;
xComPortHandle xPort;
( void ) pvParameters;
/* Obtain the address of the output buffer. Note there is no mutual
exclusion on this buffer as it is assumed only one command console interface
will be used at any one time. */
pcOutputString = FreeRTOS_CLIGetOutputBuffer();
/* Initialise the UART. */
xPort = xSerialPortInitMinimal( configCLI_BAUD_RATE, cmdQUEUE_LENGTH );
/* Send the welcome message. */
vSerialPutString( xPort, ( signed char * ) pcWelcomeMessage, ( unsigned short ) strlen( pcWelcomeMessage ) );
for( ;; )
{
/* Wait for the next character. The while loop is used in case
INCLUDE_vTaskSuspend is not set to 1 - in which case portMAX_DELAY will
be a genuine block time rather than an infinite block time. */
while( xSerialGetChar( xPort, &cRxedChar, portMAX_DELAY ) != pdPASS );
/* Ensure exclusive access to the UART Tx. */
if( xSemaphoreTake( xTxMutex, cmdMAX_MUTEX_WAIT ) == pdPASS )
{
/* Echo the character back. */
xSerialPutChar( xPort, cRxedChar, portMAX_DELAY );
/* Was it the end of the line? */
if( cRxedChar == '\n' || cRxedChar == '\r' )
{
/* Just to space the output from the input. */
vSerialPutString( xPort, ( signed char * ) pcNewLine, ( unsigned short ) strlen( pcNewLine ) );
/* See if the command is empty, indicating that the last command
is to be executed again. */
if( ucInputIndex == 0 )
{
/* Copy the last command back into the input string. */
strcpy( cInputString, cLastInputString );
}
/* Pass the received command to the command interpreter. The
command interpreter is called repeatedly until it returns
pdFALSE (indicating there is no more output) as it might
generate more than one string. */
do
{
/* Get the next output string from the command interpreter. */
xReturned = FreeRTOS_CLIProcessCommand( cInputString, pcOutputString, configCOMMAND_INT_MAX_OUTPUT_SIZE );
/* Write the generated string to the UART. */
vSerialPutString( xPort, ( signed char * ) pcOutputString, ( unsigned short ) strlen( pcOutputString ) );
} while( xReturned != pdFALSE );
/* All the strings generated by the input command have been
sent. Clear the input string ready to receive the next command.
Remember the command that was just processed first in case it is
to be processed again. */
strcpy( cLastInputString, cInputString );
ucInputIndex = 0;
memset( cInputString, 0x00, cmdMAX_INPUT_SIZE );
vSerialPutString( xPort, ( signed char * ) pcEndOfOutputMessage, ( unsigned short ) strlen( pcEndOfOutputMessage ) );
}
else
{
if( cRxedChar == '\r' )
{
/* Ignore the character. */
}
else if( ( cRxedChar == '\b' ) || ( cRxedChar == cmdASCII_DEL ) )
{
/* Backspace was pressed. Erase the last character in the
string - if any. */
if( ucInputIndex > 0 )
{
ucInputIndex--;
cInputString[ ucInputIndex ] = '\0';
}
}
else
{
/* A character was entered. Add it to the string entered so
far. When a \n is entered the complete string will be
passed to the command interpreter. */
if( ( cRxedChar >= ' ' ) && ( cRxedChar <= '~' ) )
{
if( ucInputIndex < cmdMAX_INPUT_SIZE )
{
cInputString[ ucInputIndex ] = cRxedChar;
ucInputIndex++;
}
}
}
}
/* Must ensure to give the mutex back. */
xSemaphoreGive( xTxMutex );
}
}
}
/*-----------------------------------------------------------*/
void vOutputString( const char * const pcMessage )
{
if( xSemaphoreTake( xTxMutex, cmdMAX_MUTEX_WAIT ) == pdPASS )
{
vSerialPutString( xPort, ( signed char * ) pcMessage, ( unsigned short ) strlen( pcMessage ) );
xSemaphoreGive( xTxMutex );
}
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,50 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX.h
* @brief FreeRTOS+POSIX header.
*
* This file must be included before all other FreeRTOS+POSIX includes.
*/
#ifndef _FREERTOS_POSIX_H_
#define _FREERTOS_POSIX_H_
/* FreeRTOS+POSIX platform-specific configuration headers. */
#include "FreeRTOS_POSIX_portable.h"
#include "FreeRTOS_POSIX_portable_default.h"
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "event_groups.h"
#include "semphr.h"
#include "task.h"
/* FreeRTOS+POSIX data types and internal structs. */
#include "FreeRTOS_POSIX/sys/types.h"
#include "FreeRTOS_POSIX_internal.h"
#endif /* _FREERTOS_POSIX_H_ */

View File

@ -0,0 +1,129 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef _FREERTOS_POSIX_INTERNAL_H_
#define _FREERTOS_POSIX_INTERNAL_H_
/**
* @file FreeRTOS_POSIX_internal.h
* @brief Internal structs and initializers for FreeRTOS+POSIX.
*/
/* Amazon FreeRTOS includes. */
#include "iot_doubly_linked_list.h"
/**
* @brief Mutex attribute object.
*/
#if posixconfigENABLE_PTHREAD_MUTEXATTR_T == 1
typedef struct pthread_mutexattr_internal
{
int iType; /**< Mutex type. */
} pthread_mutexattr_internal_t;
#endif
#if posixconfigENABLE_PTHREAD_MUTEX_T == 1
/**
* @brief Mutex.
*/
typedef struct pthread_mutex_internal
{
BaseType_t xIsInitialized; /**< Set to pdTRUE if this mutex is initialized, pdFALSE otherwise. */
StaticSemaphore_t xMutex; /**< FreeRTOS mutex. */
TaskHandle_t xTaskOwner; /**< Owner; used for deadlock detection and permission checks. */
pthread_mutexattr_internal_t xAttr; /**< Mutex attributes. */
} pthread_mutex_internal_t;
/**
* @brief Compile-time initializer of pthread_mutex_internal_t.
*/
#define FREERTOS_POSIX_MUTEX_INITIALIZER \
( ( ( pthread_mutex_internal_t ) \
{ \
.xIsInitialized = pdFALSE, \
.xMutex = { { 0 } }, \
.xTaskOwner = NULL, \
.xAttr = { .iType = 0 } \
} \
) \
)
#endif /* if posixconfigENABLE_PTHREAD_MUTEX_T == 1 */
#if posixconfigENABLE_PTHREAD_COND_T == 1
/**
* @brief Condition variable.
*/
typedef struct pthread_cond_internal
{
BaseType_t xIsInitialized; /**< Set to pdTRUE if this condition variable is initialized, pdFALSE otherwise. */
StaticSemaphore_t xCondWaitSemaphore; /**< Threads block on this semaphore in pthread_cond_wait. */
unsigned iWaitingThreads; /**< The number of threads currently waiting on this condition variable. */
} pthread_cond_internal_t;
/**
* @brief Compile-time initializer of pthread_cond_internal_t.
*/
#define FREERTOS_POSIX_COND_INITIALIZER \
( ( ( pthread_cond_internal_t ) \
{ \
.xIsInitialized = pdFALSE, \
.xCondWaitSemaphore = { { 0 } }, \
.iWaitingThreads = 0 \
} \
) \
)
#endif /* if posixconfigENABLE_PTHREAD_COND_T == 1 */
#if posixconfigENABLE_SEM_T == 1
/**
* @brief Semaphore type.
*/
typedef struct
{
StaticSemaphore_t xSemaphore; /**< FreeRTOS semaphore. */
int value; /**< POSIX semaphore count. */
} sem_internal_t;
#endif /* if posixconfigENABLE_SEM_T == 1 */
#if posixconfigENABLE_PTHREAD_BARRIER_T == 1
/**
* @brief Barrier object.
*/
typedef struct pthread_barrier_internal
{
unsigned uThreadCount; /**< Current number of threads that have entered barrier. */
unsigned uThreshold; /**< The count argument of pthread_barrier_init. */
StaticSemaphore_t xThreadCountSemaphore; /**< Prevents more than uThreshold threads from exiting pthread_barrier_wait at once. */
StaticEventGroup_t xBarrierEventGroup; /**< FreeRTOS event group that blocks to wait on threads entering barrier. */
} pthread_barrier_internal_t;
#endif /* if posixconfigENABLE_PTHREAD_BARRIER_T == 1 */
#endif /* _FREERTOS_POSIX_INTERNAL_H_ */

View File

@ -0,0 +1,90 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
#ifndef _FREERTOS_POSIX_INTERNAL_TYPES_H_
#define _FREERTOS_POSIX_INTERNAL_TYPES_H_
#include "FreeRTOS_POSIX_internal.h"
/*
* sys/types.h defines a POSIX type when posixconfigENABLE_PTHREAD_<TYPE>_T
* is not defined AND when posixconfigENABLE_PTHREAD_<TYPE>_T is set to 1.
* FreeRTOS_POSIX_internal.h defines internal type ONLY when
* posixconfigENABLE_PTHREAD_<TYPE>_T is set to 1.
* #else part below is to have a type defined, so the code compiles, when
* posixconfigENABLE_PTHREAD_<TYPE>_T is not defined.
*/
#if posixconfigENABLE_PTHREAD_MUTEX_T == 1
typedef pthread_mutex_internal_t PthreadMutexType_t;
#else
typedef void * PthreadMutexType_t;
#endif
#if posixconfigENABLE_PTHREAD_COND_T == 1
typedef pthread_cond_internal_t PthreadCondType_t;
#else
typedef void * PthreadCondType_t;
#endif
#if posixconfigENABLE_SEM_T == 1
typedef sem_internal_t PosixSemType_t;
#else
typedef void * PosixSemType_t;
#endif
#if posixconfigENABLE_PTHREAD_MUTEXATTR_T == 1
typedef struct pthread_mutexattr
{
uint32_t ulpthreadMutexAttrStorage;
} PthreadMutexAttrType_t;
#else
typedef void * PthreadMutexAttrType_t;
#endif
#if posixconfigENABLE_PTHREAD_ATTR_T == 1
typedef struct pthread_attr
{
uint32_t ulpthreadAttrStorage;
} PthreadAttrType_t;
#else
typedef void * PthreadAttrType_t;
#endif
#if posixconfigENABLE_PTHREAD_BARRIER_T == 1
typedef pthread_barrier_internal_t PthreadBarrierType_t;
#else
typedef void * PthreadBarrierType_t;
#endif
typedef unsigned int pthread_key_t;
typedef unsigned int pthread_once_t;
/* Once-only execution */
//typedef int pthread_once_t;
#endif /* _FREERTOS_POSIX_INTERNAL_TYPES_H_ */

View File

@ -0,0 +1,50 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
#define posixconfigENABLE_CLOCK_T 1
#define posixconfigENABLE_CLOCKID_T 1
#define posixconfigENABLE_MODE_T 1
#define posixconfigENABLE_PTHREAD_ATTR_T 1
#define posixconfigENABLE_PTHREAD_COND_T 1
#define posixconfigENABLE_PTHREAD_CONDATTR_T 1
#define posixconfigENABLE_PTHREAD_MUTEX_T 1
#define posixconfigENABLE_PTHREAD_MUTEXATTR_T 1
#define posixconfigENABLE_PTHREAD_T 1
#define posixconfigENABLE_TIME_T 1
#define posixconfigENABLE_TIMESPEC 1
#define posixconfigENABLE_ITIMERSPEC 1
#define posixconfigENABLE_SEM_T 1
#define posixconfigENABLE_PTHREAD_BARRIER_T 1
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,145 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable_default.h
* @brief Defaults for port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_DEFAULT_H_
#define _FREERTOS_POSIX_PORTABLE_DEFAULT_H_
/**
* @name The FreeRTOS task name given to pthreads.
*/
/**@{ */
#ifndef posixconfigPTHREAD_TASK_NAME
#define posixconfigPTHREAD_TASK_NAME "pthread" /**< Task name. */
#endif
/**@} */
/**
* @name the FreeRTOS timer name given to POSIX timers.
*/
/**@{ */
#ifndef posixconfigTIMER_NAME
#define posixconfigTIMER_NAME "timer" /**< Timer name. */
#endif
/**@} */
/**
* @name Defaults for POSIX message queue implementation.
*/
/**@{ */
#ifndef posixconfigMQ_MAX_MESSAGES
#define posixconfigMQ_MAX_MESSAGES 10 /**< Maximum number of messages in an mq at one time. */
#endif
#ifndef posixconfigMQ_MAX_SIZE
#define posixconfigMQ_MAX_SIZE 128 /**< Maximum size (in bytes) of each message. */
#endif
/**@} */
/**
* @name POSIX implementation-dependent constants usually defined in limits.h.
*
* They are defined here to provide portability between platforms.
*/
/**@{ */
#ifndef PTHREAD_STACK_MIN
#define PTHREAD_STACK_MIN 8 * configMINIMAL_STACK_SIZE * sizeof( StackType_t ) /**< Minimum size in bytes of thread stack storage. */
#endif
#ifndef NAME_MAX
#define NAME_MAX 64 /**< Maximum number of bytes in a filename (not including terminating null). */
#endif
#ifndef SEM_VALUE_MAX
#define SEM_VALUE_MAX 0x7FFFU /**< Maximum value of a sem_t. */
#endif
/**@} */
/**
* @name Enable typedefs of POSIX types.
*
* Set these values to 1 or 0 to enable or disable the typedefs, respectively.
* These typedefs should only be disabled if they conflict with system typedefs.
*/
/**@{ */
#ifndef posixconfigENABLE_CLOCK_T
#define posixconfigENABLE_CLOCK_T 1 /**< clock_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_CLOCKID_T
#define posixconfigENABLE_CLOCKID_T 1 /**< clockid_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_MODE_T
#define posixconfigENABLE_MODE_T 1 /**< mode_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PID_T
#define posixconfigENABLE_PID_T 1 /**< pid_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_ATTR_T
#define posixconfigENABLE_PTHREAD_ATTR_T 1 /**< pthread_attr_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_COND_T
#define posixconfigENABLE_PTHREAD_COND_T 1 /**< pthread_cond_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_CONDATTR_T
#define posixconfigENABLE_PTHREAD_CONDATTR_T 1 /**< pthread_condattr_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_MUTEX_T
#define posixconfigENABLE_PTHREAD_MUTEX_T 1 /**< pthread_mutex_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_MUTEXATTR_T
#define posixconfigENABLE_PTHREAD_MUTEXATTR_T 1 /**< pthread_mutexattr_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_T
#define posixconfigENABLE_PTHREAD_T 1 /**< pthread_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_SSIZE_T
#define posixconfigENABLE_SSIZE_T 1 /**< ssize_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_TIME_T
#define posixconfigENABLE_TIME_T 1 /**< time_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_TIMER_T
#define posixconfigENABLE_TIMER_T 1 /**< timer_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_USECONDS_T
#define posixconfigENABLE_USECONDS_T 1 /**< useconds_t in sys/types.h */
#endif
#ifndef posixconfigENABLE_TIMESPEC
#define posixconfigENABLE_TIMESPEC 1 /**< struct timespec in time.h */
#endif
#ifndef posixconfigENABLE_ITIMERSPEC
#define posixconfigENABLE_ITIMERSPEC 1 /**< struct itimerspec in time.h */
#endif
#ifndef posixconfigENABLE_SEM_T
#define posixconfigENABLE_SEM_T 1 /**< struct sem_t in semaphore.h */
#endif
#ifndef posixconfigENABLE_PTHREAD_BARRIER_T
#define posixconfigENABLE_PTHREAD_BARRIER_T 1 /**< pthread_barrier_t in sys/types.h */
#endif
/**@} */
#endif /* ifndef _FREERTOS_POSIX_PORTABLE_DEFAULT_H_ */

View File

@ -0,0 +1,60 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
/* ESP-IDF already defines the following types. */
#define posixconfigENABLE_CLOCK_T 0
#define posixconfigENABLE_CLOCKID_T 0
#define posixconfigENABLE_MODE_T 0
#define posixconfigENABLE_PTHREAD_ATTR_T 0
#define posixconfigENABLE_PTHREAD_COND_T 0
#define posixconfigENABLE_PTHREAD_CONDATTR_T 0
#define posixconfigENABLE_PTHREAD_MUTEX_T 0
#define posixconfigENABLE_PTHREAD_MUTEXATTR_T 0
#define posixconfigENABLE_PTHREAD_T 0
#define posixconfigENABLE_TIME_T 0
#define posixconfigENABLE_TIMESPEC 0
#define posixconfigENABLE_ITIMERSPEC 0
/* ESP-IDF already provides the header sched.h. Exclude FreeRTOS+POSIX sched.h by
* defining its double inclusion guard. */
#define _FREERTOS_POSIX_SCHED_H_
/* Use the FreeRTOS+POSIX time.h header instead of the ESP-IDF time.h. Disable
* ESP-IDF time.h by defining its double inclusion guard. */
#define _TIME_H_
/* Disable the timer_t type defined by ESP-IDF. */
#define __timer_t_defined
#include <sys/types.h>
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,50 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
/* Microchip includes. */
#include <sys/types.h>
/* Microchip already typedefs the following types. */
#define posixconfigENABLE_MODE_T 0
#define posixconfigENABLE_PID_T 0
#define posixconfigENABLE_SSIZE_T 0
#define posixconfigENABLE_USECONDS_T 0
/* Microchip -mnewlib compiler option supports these types. */
#define posixconfigENABLE_TIMESPEC 0
#define posixconfigENABLE_ITIMERSPEC 0
#define posixconfigENABLE_CLOCKID_T 0
#define posixconfigENABLE_TIME_T 0
#define posixconfigENABLE_TIMER_T 0
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,37 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this
* file is empty. */
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,37 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this
* file is empty. */
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,37 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this
* file is empty. */
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,37 @@
/*
* Amazon FreeRTOS+POSIX V1.0.4
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_portable.h
* @brief Port-specific configuration of FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_PORTABLE_H_
#define _FREERTOS_POSIX_PORTABLE_H_
/* This port uses the defaults in FreeRTOS_POSIX_portable_default.h, so this
* file is empty. */
#endif /* _FREERTOS_POSIX_PORTABLE_H_ */

View File

@ -0,0 +1,240 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_clock.c
* @brief Implementation of clock functions in time.h
*/
/* C standard library includes. */
#include <stddef.h>
#include <string.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/time.h"
#include "FreeRTOS_POSIX/utils.h"
/* Declaration of snprintf. The header stdio.h is not included because it
* includes conflicting symbols on some platforms. */
extern int snprintf( char * s,
size_t n,
const char * format,
... );
/*-----------------------------------------------------------*/
clock_t clock( void )
{
/* This function is currently unsupported. It will always return -1. */
return ( clock_t ) -1;
}
/*-----------------------------------------------------------*/
int clock_getcpuclockid( pid_t pid,
clockid_t * clock_id )
{
/* Silence warnings about unused parameters. */
( void ) pid;
( void ) clock_id;
/* This function is currently unsupported. It will always return EPERM. */
return EPERM;
}
/*-----------------------------------------------------------*/
int clock_getres( clockid_t clock_id,
struct timespec * res )
{
/* Silence warnings about unused parameters. */
( void ) clock_id;
/* Convert FreeRTOS tick resolution as timespec. */
if( res != NULL )
{
res->tv_sec = 0;
res->tv_nsec = NANOSECONDS_PER_TICK;
}
return 0;
}
/*-----------------------------------------------------------*/
int clock_gettime( clockid_t clock_id,
struct timespec * tp )
{
TimeOut_t xCurrentTime = { 0 };
/* Intermediate variable used to convert TimeOut_t to struct timespec.
* Also used to detect overflow issues. It must be unsigned because the
* behavior of signed integer overflow is undefined. */
uint64_t ullTickCount = 0ULL;
/* Silence warnings about unused parameters. */
( void ) clock_id;
/* Get the current tick count and overflow count. vTaskSetTimeOutState()
* is used to get these values because they are both static in tasks.c. */
vTaskSetTimeOutState( &xCurrentTime );
/* Adjust the tick count for the number of times a TickType_t has overflowed.
* portMAX_DELAY should be the maximum value of a TickType_t. */
ullTickCount = ( uint64_t ) ( xCurrentTime.xOverflowCount ) << ( sizeof( TickType_t ) * 8 );
/* Add the current tick count. */
ullTickCount += xCurrentTime.xTimeOnEntering;
/* Convert ullTickCount to timespec. */
UTILS_NanosecondsToTimespec( ( int64_t ) ullTickCount * NANOSECONDS_PER_TICK, tp );
return 0;
}
/*-----------------------------------------------------------*/
int clock_nanosleep( clockid_t clock_id,
int flags,
const struct timespec * rqtp,
struct timespec * rmtp )
{
int iStatus = 0;
TickType_t xSleepTime = 0;
struct timespec xCurrentTime = { 0 };
/* Silence warnings about unused parameters. */
( void ) clock_id;
( void ) rmtp;
( void ) flags; /* This is only ignored if INCLUDE_vTaskDelayUntil is 0. */
/* Check rqtp. */
if( UTILS_ValidateTimespec( rqtp ) == false )
{
iStatus = EINVAL;
}
/* Get current time */
if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) )
{
iStatus = EINVAL;
}
if( iStatus == 0 )
{
/* Check for absolute time sleep. */
if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME )
{
/* Get current time */
if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
{
iStatus = EINVAL;
}
/* Get number of ticks until absolute time. */
if( ( iStatus == 0 ) && ( UTILS_AbsoluteTimespecToDeltaTicks( rqtp, &xCurrentTime, &xSleepTime ) == 0 ) )
{
/* Delay until absolute time if vTaskDelayUntil is available. */
#if ( INCLUDE_vTaskDelayUntil == 1 )
/* Get the current tick count. This variable isn't declared
* at the top of the function because it's only used and needed
* if vTaskDelayUntil is available. */
TickType_t xCurrentTicks = xTaskGetTickCount();
/* Delay until absolute time. */
vTaskDelayUntil( &xCurrentTicks, xSleepTime );
#else
/* If vTaskDelayUntil isn't available, ignore the TIMER_ABSTIME flag
* and sleep for a relative time. */
vTaskDelay( xSleepTime );
#endif
}
}
else
{
/* If TIMER_ABSTIME isn't specified, convert rqtp to ticks and
* sleep for a relative time. */
if( UTILS_TimespecToTicks( rqtp, &xSleepTime ) == 0 )
{
vTaskDelay( xSleepTime );
}
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int clock_settime( clockid_t clock_id,
const struct timespec * tp )
{
/* Silence warnings about unused parameters. */
( void ) clock_id;
( void ) tp;
/* This function is currently unsupported. It will always return -1 and
* set errno to EPERM. */
errno = EPERM;
return -1;
}
/*-----------------------------------------------------------*/
int nanosleep( const struct timespec * rqtp,
struct timespec * rmtp )
{
int iStatus = 0;
TickType_t xSleepTime = 0;
/* Silence warnings about unused parameters. */
( void ) rmtp;
/* Check rqtp. */
if( UTILS_ValidateTimespec( rqtp ) == false )
{
errno = EINVAL;
iStatus = -1;
}
if( iStatus == 0 )
{
/* Convert rqtp to ticks and delay. */
if( UTILS_TimespecToTicks( rqtp, &xSleepTime ) == 0 )
{
vTaskDelay( xSleepTime );
}
}
return iStatus;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,893 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_mqueue.c
* @brief Implementation of message queue functions in mqueue.h
*/
/* C standard library includes. */
#include <string.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/fcntl.h"
#include "FreeRTOS_POSIX/mqueue.h"
#include "FreeRTOS_POSIX/utils.h"
/**
* @brief Element of the FreeRTOS queues that store mq data.
*/
typedef struct QueueElement
{
char * pcData; /**< Data in queue. Type char* to match msg_ptr. */
size_t xDataSize; /**< Size of data pointed by pcData. */
} QueueElement_t;
/**
* @brief Data structure of an mq.
*
* FreeRTOS isn't guaranteed to have a file-like abstraction, so message
* queues in this implementation are stored as a linked list (in RAM).
*/
typedef struct QueueListElement
{
Link_t xLink; /**< Pointer to the next element in the list. */
QueueHandle_t xQueue; /**< FreeRTOS queue handle. */
size_t xOpenDescriptors; /**< Number of threads that have opened this queue. */
char * pcName; /**< Null-terminated queue name. */
struct mq_attr xAttr; /**< Queue attibutes. */
BaseType_t xPendingUnlink; /**< If pdTRUE, this queue will be unlinked once all descriptors close. */
} QueueListElement_t;
/*-----------------------------------------------------------*/
/**
* @brief Convert an absolute timespec into a tick timeout, taking into account
* queue flags.
*
* @param[in] lMessageQueueFlags Message queue flags to consider.
* @param[in] pxAbsoluteTimeout The absolute timespec to convert.
* @param[out] pxTimeoutTicks Output parameter of the timeout in ticks.
*
* @return 0 if successful; EINVAL if pxAbsoluteTimeout is invalid, or ETIMEDOUT
* if pxAbsoluteTimeout is in the past.
*/
static int prvCalculateTickTimeout( long lMessageQueueFlags,
const struct timespec * const pxAbsoluteTimeout,
TickType_t * pxTimeoutTicks );
/**
* @brief Add a new queue to the queue list.
*
* @param[out] ppxMessageQueue Pointer to new queue.
* @param[in] pxAttr mq_attr of the new queue.
* @param[in] pcName Name of new queue.
* @param[in] xNameLength Length of pcName.
*
* @return pdTRUE if the queue is found; pdFALSE otherwise.
*/
static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue,
const struct mq_attr * const pxAttr,
const char * const pcName,
size_t xNameLength );
/**
* @brief Free all the resources used by a message queue.
*
* @param[out] pxMessageQueue Pointer to queue to free.
*
* @return nothing
*/
static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue );
/**
* @brief Attempt to find the queue identified by pcName or xMqId in the queue list.
*
* Matches queues by pcName first; if pcName is NULL, matches by xMqId.
* @param[out] ppxQueueListElement Output parameter set when queue is found.
* @param[in] pcName A queue name to match.
* @param[in] xMessageQueueDescriptor A queue descriptor to match.
*
* @return pdTRUE if the queue is found; pdFALSE otherwise.
*/
static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,
const char * const pcName,
mqd_t xMessageQueueDescriptor );
/**
* @brief Initialize the queue list.
*
* Performs initialization of the queue list mutex and queue list head.
*
* @return nothing
*/
static void prvInitializeQueueList( void );
/**
* @brief Checks that pcName is a valid name for a message queue.
*
* Also outputs the length of pcName.
* @param[in] pcName The name to check.
* @param[out] pxNameLength Output parameter for name length.
*
* @return pdTRUE if the name is valid; pdFALSE otherwise.
*/
static BaseType_t prvValidateQueueName( const char * const pcName,
size_t * pxNameLength );
/**
* @brief Guards access to the list of message queues.
*/
static StaticSemaphore_t xQueueListMutex = { { 0 }, .u = { 0 } };
/**
* @brief Head of the linked list of queues.
*/
static Link_t xQueueListHead = { 0 };
/*-----------------------------------------------------------*/
static int prvCalculateTickTimeout( long lMessageQueueFlags,
const struct timespec * const pxAbsoluteTimeout,
TickType_t * pxTimeoutTicks )
{
int iStatus = 0;
/* Check for nonblocking queue. */
if( lMessageQueueFlags & O_NONBLOCK )
{
/* No additional checks are done for nonblocking queues. Timeout is 0. */
*pxTimeoutTicks = 0;
}
else
{
/* No absolute timeout given. Block forever. */
if( pxAbsoluteTimeout == NULL )
{
*pxTimeoutTicks = portMAX_DELAY;
}
else
{
struct timespec xCurrentTime = { 0 };
/* Check that the given timespec is valid. */
if( UTILS_ValidateTimespec( pxAbsoluteTimeout ) == false )
{
iStatus = EINVAL;
}
/* Get current time */
if( ( iStatus == 0 ) && ( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 ) )
{
iStatus = EINVAL;
}
/* Convert absolute timespec to ticks. */
if( ( iStatus == 0 ) &&
( UTILS_AbsoluteTimespecToDeltaTicks( pxAbsoluteTimeout, &xCurrentTime, pxTimeoutTicks ) != 0 ) )
{
iStatus = ETIMEDOUT;
}
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
static BaseType_t prvCreateNewMessageQueue( QueueListElement_t ** ppxMessageQueue,
const struct mq_attr * const pxAttr,
const char * const pcName,
size_t xNameLength )
{
BaseType_t xStatus = pdTRUE;
/* Allocate space for a new queue element. */
*ppxMessageQueue = pvPortMalloc( sizeof( QueueListElement_t ) );
/* Check that memory allocation succeeded. */
if( *ppxMessageQueue == NULL )
{
xStatus = pdFALSE;
}
/* Create the FreeRTOS queue. */
if( xStatus == pdTRUE )
{
( *ppxMessageQueue )->xQueue =
xQueueCreate( pxAttr->mq_maxmsg, sizeof( QueueElement_t ) );
/* Check that queue creation succeeded. */
if( ( *ppxMessageQueue )->xQueue == NULL )
{
vPortFree( *ppxMessageQueue );
xStatus = pdFALSE;
}
}
if( xStatus == pdTRUE )
{
/* Allocate space for the queue name plus null-terminator. */
( *ppxMessageQueue )->pcName = pvPortMalloc( xNameLength + 1 );
/* Check that memory was successfully allocated for queue name. */
if( ( *ppxMessageQueue )->pcName == NULL )
{
vQueueDelete( ( *ppxMessageQueue )->xQueue );
vPortFree( *ppxMessageQueue );
xStatus = pdFALSE;
}
else
{
/* Copy queue name. Copying xNameLength+1 will cause strncpy to add
* the null-terminator. */
( void ) strncpy( ( *ppxMessageQueue )->pcName, pcName, xNameLength + 1 );
}
}
if( xStatus == pdTRUE )
{
/* Copy attributes. */
( *ppxMessageQueue )->xAttr = *pxAttr;
/* A newly-created queue will have 1 open descriptor for it. */
( *ppxMessageQueue )->xOpenDescriptors = 1;
/* A newly-created queue will not be pending unlink. */
( *ppxMessageQueue )->xPendingUnlink = pdFALSE;
/* Add the new queue to the list. */
listADD( &xQueueListHead, &( *ppxMessageQueue )->xLink );
}
return xStatus;
}
/*-----------------------------------------------------------*/
static void prvDeleteMessageQueue( const QueueListElement_t * const pxMessageQueue )
{
QueueElement_t xQueueElement = { 0 };
/* Free all data in the queue. It's assumed that no more data will be added
* to the queue, so xQueueReceive does not block. */
while( xQueueReceive( pxMessageQueue->xQueue,
( void * ) &xQueueElement,
0 ) == pdTRUE )
{
vPortFree( xQueueElement.pcData );
}
/* Free memory used by this message queue. */
vQueueDelete( pxMessageQueue->xQueue );
vPortFree( ( void * ) pxMessageQueue->pcName );
vPortFree( ( void * ) pxMessageQueue );
}
/*-----------------------------------------------------------*/
static BaseType_t prvFindQueueInList( QueueListElement_t ** const ppxQueueListElement,
const char * const pcName,
mqd_t xMessageQueueDescriptor )
{
Link_t * pxQueueListLink = NULL;
QueueListElement_t * pxMessageQueue = NULL;
BaseType_t xQueueFound = pdFALSE;
/* Iterate through the list of queues. */
listFOR_EACH( pxQueueListLink, &xQueueListHead )
{
pxMessageQueue = listCONTAINER( pxQueueListLink, QueueListElement_t, xLink );
/* Match by name first if provided. */
if( ( pcName != NULL ) && ( strcmp( pxMessageQueue->pcName, pcName ) == 0 ) )
{
xQueueFound = pdTRUE;
break;
}
/* If name doesn't match, match by descriptor. */
else
{
if( ( mqd_t ) pxMessageQueue == xMessageQueueDescriptor )
{
xQueueFound = pdTRUE;
break;
}
}
}
/* If the queue was found, set the output parameter. */
if( ( xQueueFound == pdTRUE ) && ( ppxQueueListElement != NULL ) )
{
*ppxQueueListElement = pxMessageQueue;
}
return xQueueFound;
}
/*-----------------------------------------------------------*/
static void prvInitializeQueueList( void )
{
/* Keep track of whether the queue list has been initialized. */
static BaseType_t xQueueListInitialized = pdFALSE;
/* Check if queue list needs to be initialized. */
if( xQueueListInitialized == pdFALSE )
{
/* Initialization must be in a critical section to prevent two threads
* from initializing at the same time. */
taskENTER_CRITICAL();
/* Check again that queue list is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if( xQueueListInitialized == pdFALSE )
{
/* Initialize the queue list mutex and list head. */
( void ) xSemaphoreCreateMutexStatic( &xQueueListMutex );
listINIT_HEAD( &xQueueListHead );
xQueueListInitialized = pdTRUE;
}
/* Exit the critical section. */
taskEXIT_CRITICAL();
}
}
/*-----------------------------------------------------------*/
static BaseType_t prvValidateQueueName( const char * const pcName,
size_t * pxNameLength )
{
BaseType_t xStatus = pdTRUE;
size_t xNameLength = 0;
/* All message queue names must start with '/'. */
if( pcName[ 0 ] != '/' )
{
xStatus = pdFALSE;
}
else
{
/* Get the length of pcName, excluding the first '/' and null-terminator. */
xNameLength = UTILS_strnlen( pcName, NAME_MAX + 2 );
if( xNameLength == NAME_MAX + 2 )
{
/* Name too long. */
xStatus = pdFALSE;
}
else
{
/* Name length passes, set output parameter. */
*pxNameLength = xNameLength;
}
}
return xStatus;
}
/*-----------------------------------------------------------*/
int mq_close( mqd_t mqdes )
{
int iStatus = 0;
QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
BaseType_t xQueueRemoved = pdFALSE;
/* Initialize the queue list, if needed. */
prvInitializeQueueList();
/* Lock the mutex that guards access to the queue list. This call will
* never fail because it blocks forever. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
/* Attempt to find the message queue based on the given descriptor. */
if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )
{
/* Decrement the number of open descriptors. */
if( pxMessageQueue->xOpenDescriptors > 0 )
{
pxMessageQueue->xOpenDescriptors--;
}
/* Check if the queue has any more open descriptors. */
if( pxMessageQueue->xOpenDescriptors == 0 )
{
/* If no open descriptors remain and mq_unlink has already been called,
* remove the queue. */
if( pxMessageQueue->xPendingUnlink == pdTRUE )
{
listREMOVE( &pxMessageQueue->xLink );
/* Set the flag to delete the queue. Deleting the queue is deferred
* until xQueueListMutex is released. */
xQueueRemoved = pdTRUE;
}
/* Otherwise, wait for the call to mq_unlink. */
else
{
pxMessageQueue->xPendingUnlink = pdTRUE;
}
}
}
else
{
/* Queue not found; bad descriptor. */
errno = EBADF;
iStatus = -1;
}
/* Release the mutex protecting the queue list. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
/* Delete all resources used by the queue if needed. */
if( xQueueRemoved == pdTRUE )
{
prvDeleteMessageQueue( pxMessageQueue );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int mq_getattr( mqd_t mqdes,
struct mq_attr * mqstat )
{
int iStatus = 0;
QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
/* Lock the mutex that guards access to the queue list. This call will
* never fail because it blocks forever. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
/* Find the mq referenced by mqdes. */
if( prvFindQueueInList( NULL, NULL, mqdes ) == pdTRUE )
{
/* Update the number of messages in the queue and copy the attributes
* into mqstat. */
pxMessageQueue->xAttr.mq_curmsgs = ( long ) uxQueueMessagesWaiting( pxMessageQueue->xQueue );
*mqstat = pxMessageQueue->xAttr;
}
else
{
/* Queue not found; bad descriptor. */
errno = EBADF;
iStatus = -1;
}
/* Release the mutex protecting the queue list. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
return iStatus;
}
/*-----------------------------------------------------------*/
mqd_t mq_open( const char * name,
int oflag,
mode_t mode,
struct mq_attr * attr )
{
mqd_t xMessageQueue = NULL;
size_t xNameLength = 0;
/* Default mq_attr. */
struct mq_attr xQueueCreationAttr =
{
.mq_flags = 0,
.mq_maxmsg = posixconfigMQ_MAX_MESSAGES,
.mq_msgsize = posixconfigMQ_MAX_SIZE,
.mq_curmsgs = 0
};
/* Silence warnings about unused parameters. */
( void ) mode;
/* Initialize the queue list, if needed. */
prvInitializeQueueList();
/* Check queue name. */
if( prvValidateQueueName( name, &xNameLength ) == pdFALSE )
{
/* Invalid name. */
errno = EINVAL;
xMessageQueue = ( mqd_t ) -1;
}
/* Check attributes, if given. */
if( xMessageQueue == NULL )
{
if( ( oflag & O_CREAT ) && ( attr != NULL ) && ( ( attr->mq_maxmsg <= 0 ) || ( attr->mq_msgsize <= 0 ) ) )
{
/* Invalid mq_attr.mq_maxmsg or mq_attr.mq_msgsize. */
errno = EINVAL;
xMessageQueue = ( mqd_t ) -1;
}
}
if( xMessageQueue == NULL )
{
/* Lock the mutex that guards access to the queue list. This call will
* never fail because it blocks forever. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
/* Search the queue list to check if the queue exists. */
if( prvFindQueueInList( ( QueueListElement_t ** ) &xMessageQueue,
name,
( mqd_t ) NULL ) == pdTRUE )
{
/* If the mq exists, check that this function wasn't called with
* O_CREAT and O_EXCL. */
if( ( oflag & O_EXCL ) && ( oflag & O_CREAT ) )
{
errno = EEXIST;
xMessageQueue = ( mqd_t ) -1;
}
else
{
/* Check if the mq has been unlinked and is pending removal. */
if( ( ( QueueListElement_t * ) xMessageQueue )->xPendingUnlink == pdTRUE )
{
/* Queue pending deletion. Don't allow it to be re-opened. */
errno = EINVAL;
xMessageQueue = ( mqd_t ) -1;
}
else
{
/* Increase count of open file descriptors for queue. */
( ( QueueListElement_t * ) xMessageQueue )->xOpenDescriptors++;
}
}
}
/* Queue does not exist. */
else
{
/* Only create the new queue if O_CREAT was specified. */
if( oflag & O_CREAT )
{
/* Copy attributes if provided. */
if( attr != NULL )
{
xQueueCreationAttr = *attr;
}
/* Copy oflags. */
xQueueCreationAttr.mq_flags = ( long ) oflag;
/* Create the new message queue. */
if( prvCreateNewMessageQueue( ( QueueListElement_t ** ) &xMessageQueue,
&xQueueCreationAttr,
name,
xNameLength ) == pdFALSE )
{
errno = ENOSPC;
xMessageQueue = ( mqd_t ) -1;
}
}
else
{
errno = ENOENT;
xMessageQueue = ( mqd_t ) -1;
}
}
/* Release the mutex protecting the queue list. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
}
return xMessageQueue;
}
/*-----------------------------------------------------------*/
ssize_t mq_receive( mqd_t mqdes,
char * msg_ptr,
size_t msg_len,
unsigned int * msg_prio )
{
return mq_timedreceive( mqdes, msg_ptr, msg_len, msg_prio, NULL );
}
/*-----------------------------------------------------------*/
int mq_send( mqd_t mqdes,
const char * msg_ptr,
size_t msg_len,
unsigned msg_prio )
{
return mq_timedsend( mqdes, msg_ptr, msg_len, msg_prio, NULL );
}
/*-----------------------------------------------------------*/
ssize_t mq_timedreceive( mqd_t mqdes,
char * msg_ptr,
size_t msg_len,
unsigned * msg_prio,
const struct timespec * abstime )
{
ssize_t xStatus = 0;
int iCalculateTimeoutReturn = 0;
TickType_t xTimeoutTicks = 0;
QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
QueueElement_t xReceiveData = { 0 };
/* Silence warnings about unused parameters. */
( void ) msg_prio;
/* Lock the mutex that guards access to the queue list. This call will
* never fail because it blocks forever. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
/* Find the mq referenced by mqdes. */
if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )
{
/* Queue not found; bad descriptor. */
errno = EBADF;
xStatus = -1;
}
/* Verify that msg_len is large enough. */
if( xStatus == 0 )
{
if( msg_len < ( size_t ) pxMessageQueue->xAttr.mq_msgsize )
{
/* msg_len too small. */
errno = EMSGSIZE;
xStatus = -1;
}
}
if( xStatus == 0 )
{
/* Convert abstime to a tick timeout. */
iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,
abstime,
&xTimeoutTicks );
if( iCalculateTimeoutReturn != 0 )
{
errno = iCalculateTimeoutReturn;
xStatus = -1;
}
}
/* Release the mutex protecting the queue list. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
if( xStatus == 0 )
{
/* Receive data from the FreeRTOS queue. */
if( xQueueReceive( pxMessageQueue->xQueue,
&xReceiveData,
xTimeoutTicks ) == pdFALSE )
{
/* If queue receive fails, set the appropriate errno. */
if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )
{
/* Set errno to EAGAIN for nonblocking mq. */
errno = EAGAIN;
}
else
{
/* Otherwise, set errno to ETIMEDOUT. */
errno = ETIMEDOUT;
}
xStatus = -1;
}
}
if( xStatus == 0 )
{
/* Get the length of data for return value. */
xStatus = ( ssize_t ) xReceiveData.xDataSize;
/* Copy received data into given buffer, then free it. */
( void ) memcpy( msg_ptr, xReceiveData.pcData, xReceiveData.xDataSize );
vPortFree( xReceiveData.pcData );
}
return xStatus;
}
/*-----------------------------------------------------------*/
int mq_timedsend( mqd_t mqdes,
const char * msg_ptr,
size_t msg_len,
unsigned int msg_prio,
const struct timespec * abstime )
{
int iStatus = 0, iCalculateTimeoutReturn = 0;
TickType_t xTimeoutTicks = 0;
QueueListElement_t * pxMessageQueue = ( QueueListElement_t * ) mqdes;
QueueElement_t xSendData = { 0 };
/* Silence warnings about unused parameters. */
( void ) msg_prio;
/* Lock the mutex that guards access to the queue list. This call will
* never fail because it blocks forever. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
/* Find the mq referenced by mqdes. */
if( prvFindQueueInList( NULL, NULL, mqdes ) == pdFALSE )
{
/* Queue not found; bad descriptor. */
errno = EBADF;
iStatus = -1;
}
/* Verify that mq_msgsize is large enough. */
if( iStatus == 0 )
{
if( msg_len > ( size_t ) pxMessageQueue->xAttr.mq_msgsize )
{
/* msg_len too large. */
errno = EMSGSIZE;
iStatus = -1;
}
}
if( iStatus == 0 )
{
/* Convert abstime to a tick timeout. */
iCalculateTimeoutReturn = prvCalculateTickTimeout( pxMessageQueue->xAttr.mq_flags,
abstime,
&xTimeoutTicks );
if( iCalculateTimeoutReturn != 0 )
{
errno = iCalculateTimeoutReturn;
iStatus = -1;
}
}
/* Release the mutex protecting the queue list. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
/* Allocate memory for the message. */
if( iStatus == 0 )
{
xSendData.xDataSize = msg_len;
xSendData.pcData = pvPortMalloc( msg_len );
/* Check that memory allocation succeeded. */
if( xSendData.pcData == NULL )
{
/* msg_len too large. */
errno = EMSGSIZE;
iStatus = -1;
}
else
{
/* Copy the data to send. */
( void ) memcpy( xSendData.pcData, msg_ptr, msg_len );
}
}
if( iStatus == 0 )
{
/* Send data to the FreeRTOS queue. */
if( xQueueSend( pxMessageQueue->xQueue,
&xSendData,
xTimeoutTicks ) == pdFALSE )
{
/* If queue send fails, set the appropriate errno. */
if( pxMessageQueue->xAttr.mq_flags & O_NONBLOCK )
{
/* Set errno to EAGAIN for nonblocking mq. */
errno = EAGAIN;
}
else
{
/* Otherwise, set errno to ETIMEDOUT. */
errno = ETIMEDOUT;
}
/* Free the allocated queue data. */
vPortFree( xSendData.pcData );
iStatus = -1;
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int mq_unlink( const char * name )
{
int iStatus = 0;
size_t xNameSize = 0;
BaseType_t xQueueRemoved = pdFALSE;
QueueListElement_t * pxMessageQueue = NULL;
/* Initialize the queue list, if needed. */
prvInitializeQueueList();
/* Check queue name. */
if( prvValidateQueueName( name, &xNameSize ) == pdFALSE )
{
/* Error with mq name. */
errno = EINVAL;
iStatus = -1;
}
if( iStatus == 0 )
{
/* Lock the mutex that guards access to the queue list. This call will
* never fail because it blocks forever. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &xQueueListMutex, portMAX_DELAY );
/* Check if the named queue exists. */
if( prvFindQueueInList( &pxMessageQueue, name, ( mqd_t ) NULL ) == pdTRUE )
{
/* If the queue exists and there are no open descriptors to it,
* remove it from the list. */
if( pxMessageQueue->xOpenDescriptors == 0 )
{
listREMOVE( &pxMessageQueue->xLink );
/* Set the flag to delete the queue. Deleting the queue is deferred
* until xQueueListMutex is released. */
xQueueRemoved = pdTRUE;
}
else
{
/* If the queue has open descriptors, set the pending unlink flag
* so that mq_close will free its resources. */
pxMessageQueue->xPendingUnlink = pdTRUE;
}
}
else
{
/* The named message queue doesn't exist. */
errno = ENOENT;
iStatus = -1;
}
/* Release the mutex protecting the queue list. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &xQueueListMutex );
}
/* Delete all resources used by the queue if needed. */
if( xQueueRemoved == pdTRUE )
{
prvDeleteMessageQueue( pxMessageQueue );
}
return iStatus;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,699 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_pthread.c
* @brief Implementation of thread functions in pthread.h
*/
/* C standard library includes. */
#include <stddef.h>
#include <string.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/pthread.h"
/**
* @brief Thread attribute object.
*/
typedef struct pthread_attr_internal
{
uint16_t usStackSize; /**< Stack size. */
uint16_t usSchedPriorityDetachState; /**< Schedule priority 15 bits (LSB) Detach state: 1 bits (MSB) */
} pthread_attr_internal_t;
#define pthreadDETACH_STATE_MASK 0x8000
#define pthreadSCHED_PRIORITY_MASK 0x7FFF
#define pthreadDETACH_STATE_SHIFT 15
#define pthreadGET_SCHED_PRIORITY( var ) ( ( var ) & ( pthreadSCHED_PRIORITY_MASK ) )
#define pthreadIS_JOINABLE( var ) ( ( ( var ) & ( pthreadDETACH_STATE_MASK ) ) == pthreadDETACH_STATE_MASK )
struct _pthread_key_data
{
int is_used;
void (*destructor)(void *parameter);
};
typedef struct _pthread_key_data _pthread_key_data_t;
#define PTHREAD_KEY_MAX 32
/**
* @brief Thread object.
*/
typedef struct pthread_internal
{
pthread_attr_internal_t xAttr; /**< Thread attributes. */
void * ( *pvStartRoutine )( void * ); /**< Application thread function. */
void * xTaskArg; /**< Arguments for application thread function. */
TaskHandle_t xTaskHandle; /**< FreeRTOS task handle. */
StaticSemaphore_t xJoinBarrier; /**< Synchronizes the two callers of pthread_join. */
StaticSemaphore_t xJoinMutex; /**< Ensures that only one other thread may join this thread. */
void * xReturn; /**< Return value of pvStartRoutine. */
void** tls;
} pthread_internal_t;
/**
* @brief Terminates the calling thread.
*
* For joinable threads, this function waits for pthread_join. Otherwise,
* it deletes the thread and frees up resources used by the thread.
*
* @return This function does not return.
*/
static void prvExitThread( void );
/**
* @brief Wrapper function for the user's thread routine.
*
* This function is executed as a FreeRTOS task function.
* @param[in] pxArg A pointer to a pthread_internal_t.
*
* @return nothing
*/
static void prvRunThread( void * pxArg );
/**
* @brief Default pthread_attr_t.
*/
static const pthread_attr_internal_t xDefaultThreadAttributes =
{
.usStackSize = PTHREAD_STACK_MIN,
.usSchedPriorityDetachState = ( ( uint16_t ) tskIDLE_PRIORITY & pthreadSCHED_PRIORITY_MASK ) | ( PTHREAD_CREATE_JOINABLE << pthreadDETACH_STATE_SHIFT ),
};
/*-----------------------------------------------------------*/
static void prvExitThread( void )
{
pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self();
/* If this thread is joinable, wait for a call to pthread_join. */
if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
{
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
/* Suspend until the call to pthread_join. The caller of pthread_join
* will perform cleanup. */
vTaskSuspend( NULL );
}
else
{
/* For a detached thread, perform cleanup of thread object. */
vPortFree( pxThread );
vTaskDelete( NULL );
}
}
/*-----------------------------------------------------------*/
static void prvRunThread( void * pxArg )
{
pthread_internal_t * pxThread = ( pthread_internal_t * ) pxArg;
/* Run the thread routine. */
pxThread->xReturn = pxThread->pvStartRoutine( ( void * ) pxThread->xTaskArg );
/* Exit once finished. This function does not return. */
prvExitThread();
}
/*-----------------------------------------------------------*/
int pthread_attr_destroy( pthread_attr_t * attr )
{
( void ) attr;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_attr_getdetachstate( const pthread_attr_t * attr,
int * detachstate )
{
pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
if( pthreadIS_JOINABLE( pxAttr->usSchedPriorityDetachState ) )
{
*detachstate = PTHREAD_CREATE_JOINABLE;
}
else
{
*detachstate = PTHREAD_CREATE_DETACHED;
}
return 0;
}
/*-----------------------------------------------------------*/
int pthread_attr_getschedparam( const pthread_attr_t * attr,
struct sched_param * param )
{
pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
param->sched_priority = ( int ) ( pthreadGET_SCHED_PRIORITY( pxAttr->usSchedPriorityDetachState ) );
return 0;
}
/*-----------------------------------------------------------*/
int pthread_attr_getstacksize( const pthread_attr_t * attr,
size_t * stacksize )
{
pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
*stacksize = ( size_t ) pxAttr->usStackSize;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_attr_init( pthread_attr_t * attr )
{
/* Copy the default values into the new thread attributes object. */
*( ( pthread_attr_internal_t * ) ( attr ) ) = xDefaultThreadAttributes;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_attr_setdetachstate( pthread_attr_t * attr,
int detachstate )
{
int iStatus = 0;
pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
if( ( detachstate != PTHREAD_CREATE_DETACHED ) && ( detachstate != PTHREAD_CREATE_JOINABLE ) )
{
iStatus = EINVAL;
}
else
{
/* clear and then set msb bit to detachstate) */
pxAttr->usSchedPriorityDetachState &= ~pthreadDETACH_STATE_MASK;
pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) detachstate << pthreadDETACH_STATE_SHIFT );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_attr_setschedparam( pthread_attr_t * attr,
const struct sched_param * param )
{
int iStatus = 0;
pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
/* Check for NULL param. */
if( param == NULL )
{
iStatus = EINVAL;
}
/* Ensure that param.sched_priority is valid. */
if( ( iStatus == 0 ) &&
( ( param->sched_priority > sched_get_priority_max( SCHED_OTHER ) ) ||
( param->sched_priority < 0 ) ) )
{
iStatus = ENOTSUP;
}
/* Set the sched_param. */
if( iStatus == 0 )
{
/* clear and then set 15 LSB to schedule priority) */
pxAttr->usSchedPriorityDetachState &= ~pthreadSCHED_PRIORITY_MASK;
pxAttr->usSchedPriorityDetachState |= ( ( uint16_t ) param->sched_priority );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_attr_setschedpolicy( pthread_attr_t * attr,
int policy )
{
/* Silence warnings about unused parameters. */
( void ) attr;
( void ) policy;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_attr_setstacksize( pthread_attr_t * attr,
size_t stacksize )
{
int iStatus = 0;
pthread_attr_internal_t * pxAttr = ( pthread_attr_internal_t * ) ( attr );
if( stacksize < PTHREAD_STACK_MIN )
{
iStatus = EINVAL;
}
else
{
pxAttr->usStackSize = ( uint16_t ) stacksize;
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_create( pthread_t * thread,
const pthread_attr_t * attr,
void *( *startroutine )( void * ),
void * arg )
{
int iStatus = 0;
pthread_internal_t * pxThread = NULL;
struct sched_param xSchedParam = { .sched_priority = tskIDLE_PRIORITY };
/* Allocate memory for new thread object. */
pxThread = ( pthread_internal_t * ) pvPortMalloc( sizeof( pthread_internal_t ) );
if( pxThread == NULL )
{
/* No memory. */
iStatus = EAGAIN;
} else {
memset((void*)pxThread, 0, sizeof(pthread_internal_t));
pxThread->tls = NULL;
}
if( iStatus == 0 )
{
/* No attributes given, use default attributes. */
if( attr == NULL )
{
pxThread->xAttr = xDefaultThreadAttributes;
}
/* Otherwise, use provided attributes. */
else
{
pxThread->xAttr = *( ( pthread_attr_internal_t * ) ( attr ) );
}
/* Get priority from attributes */
xSchedParam.sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState );
/* Set argument and start routine. */
pxThread->xTaskArg = arg;
pxThread->pvStartRoutine = startroutine;
/* If this thread is joinable, create the synchronization mechanisms for
* pthread_join. */
if( pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
{
/* These calls will not fail when their arguments aren't NULL. */
( void ) xSemaphoreCreateMutexStatic( &pxThread->xJoinMutex );
( void ) xSemaphoreCreateBinaryStatic( &pxThread->xJoinBarrier );
}
}
if( iStatus == 0 )
{
/* Suspend all tasks to create a critical section. This ensures that
* the new thread doesn't exit before a tag is assigned. */
vTaskSuspendAll();
/* Create the FreeRTOS task that will run the pthread. */
if( xTaskCreate( prvRunThread,
posixconfigPTHREAD_TASK_NAME,
( uint16_t ) ( pxThread->xAttr.usStackSize / sizeof( StackType_t ) ),
( void * ) pxThread,
xSchedParam.sched_priority,
&pxThread->xTaskHandle ) != pdPASS )
{
/* Task creation failed, no memory. */
vPortFree( pxThread );
iStatus = EAGAIN;
}
else
{
/* Store the pointer to the thread object in the task tag. */
vTaskSetApplicationTaskTag( pxThread->xTaskHandle, ( TaskHookFunction_t ) pxThread );
/* Set the thread object for the user. */
*thread = ( pthread_t ) pxThread;
}
/* End the critical section. */
xTaskResumeAll();
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_getschedparam( pthread_t thread,
int * policy,
struct sched_param * param )
{
int iStatus = 0;
pthread_internal_t * pxThread = ( pthread_internal_t * ) thread;
*policy = SCHED_OTHER;
param->sched_priority = ( int ) pthreadGET_SCHED_PRIORITY( pxThread->xAttr.usSchedPriorityDetachState );
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_equal( pthread_t t1,
pthread_t t2 )
{
return t1 == t2;
}
/*-----------------------------------------------------------*/
void pthread_exit( void * value_ptr )
{
pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread_self();
/* Set the return value. */
pxThread->xReturn = value_ptr;
/* Exit this thread. */
prvExitThread();
}
/*-----------------------------------------------------------*/
int pthread_join( pthread_t pthread,
void ** retval )
{
int iStatus = 0;
pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread;
/* Make sure pthread is joinable. Otherwise, this function would block
* forever waiting for an unjoinable thread. */
if( !pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
{
iStatus = EDEADLK;
}
/* Only one thread may attempt to join another. Lock the join mutex
* to prevent other threads from calling pthread_join on the same thread. */
if( iStatus == 0 )
{
if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinMutex, 0 ) != pdPASS )
{
/* Another thread has already joined the requested thread, which would
* cause this thread to wait forever. */
iStatus = EDEADLK;
}
}
/* Attempting to join the calling thread would cause a deadlock. */
if( iStatus == 0 )
{
if( pthread_equal( pthread_self(), pthread ) != 0 )
{
iStatus = EDEADLK;
}
}
if( iStatus == 0 )
{
/* Wait for the joining thread to finish. Because this call waits forever,
* it should never fail. */
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier, portMAX_DELAY );
/* Create a critical section to clean up the joined thread. */
vTaskSuspendAll();
/* Release xJoinBarrier and delete it. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
/* Release xJoinMutex and delete it. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );
/* Delete the FreeRTOS task that ran the thread. */
vTaskDelete( pxThread->xTaskHandle );
/* Set the return value. */
if( retval != NULL )
{
*retval = pxThread->xReturn;
}
/* Free the thread object. */
vPortFree( pxThread );
/* End the critical section. */
xTaskResumeAll();
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_detach(pthread_t pthread)
{
int iStatus = 0;
pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread;
eTaskState pThreadState;
/* Make sure pthread is joinable. */
if( !pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
{
iStatus = EINVAL;
}
if ( iStatus == 0 )
{
/* Create a critical section to verify that pthread is joinable. */
vTaskSuspendAll();
pThreadState = eTaskGetState(pxThread->xTaskHandle);
/* Thread has been deleted or is invalid. */
if ( (pThreadState == eDeleted) || (pThreadState == eInvalid) )
{
iStatus = EINVAL;
}
else
{
/* Release xJoinBarrier and delete it. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinBarrier );
/* Release xJoinMutex and delete it. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxThread->xJoinMutex );
/* Thread has been finished */
if ( pThreadState == eSuspended )
{
/* Delete the FreeRTOS task that ran the thread. */
vTaskDelete( pxThread->xTaskHandle );
/* Free the thread object. */
vPortFree( pxThread );
}
else
{
/* Thread is in the running or ready state. */
pthread_attr_setdetachstate( (pthread_attr_t *) &pxThread->xAttr, PTHREAD_CREATE_DETACHED );
}
}
/* End the critical section. */
xTaskResumeAll();
}
return iStatus;
}
/*-----------------------------------------------------------*/
pthread_t pthread_self( void )
{
/* Return a reference to this pthread object, which is stored in the
* FreeRTOS task tag. */
return ( pthread_t ) xTaskGetApplicationTaskTag( NULL );
}
/*-----------------------------------------------------------*/
int pthread_setschedparam( pthread_t thread,
int policy,
const struct sched_param * param )
{
int iStatus = 0;
pthread_internal_t * pxThread = ( pthread_internal_t * ) thread;
/* Silence compiler warnings about unused parameters. */
( void ) policy;
/* Copy the given sched_param. */
iStatus = pthread_attr_setschedparam( ( pthread_attr_t * ) &pxThread->xAttr, param );
if( iStatus == 0 )
{
/* Change the priority of the FreeRTOS task. */
vTaskPrioritySet( pxThread->xTaskHandle, param->sched_priority );
}
return iStatus;
}
static _pthread_key_data_t _thread_keys[PTHREAD_KEY_MAX];
void pthread_key_system_init()
{
memset(&_thread_keys[0], 0, sizeof(_thread_keys));
}
void *pthread_getspecific(pthread_key_t key)
{
struct pthread_internal* ptd;
if (pthread_self() == NULL) return NULL;
/* get pthread data from user data of thread */
ptd = (pthread_internal_t *)pthread_self();
if (ptd->tls == NULL)
return NULL;
if ((key < PTHREAD_KEY_MAX) && (_thread_keys[key].is_used))
return ptd->tls[key];
return NULL;
}
int pthread_setspecific(pthread_key_t key, const void *value)
{
struct pthread_internal* ptd;
if (pthread_self() == NULL) return EINVAL;
/* get pthread data from user data of thread */
ptd = (pthread_internal_t *)pthread_self();
/* check tls area */
if (ptd->tls == NULL) {
ptd->tls = (void**)pvPortMalloc(sizeof(void*) * PTHREAD_KEY_MAX);
}
if ((key < PTHREAD_KEY_MAX) && _thread_keys[key].is_used) {
ptd->tls[key] = (void *)value;
return 0;
}
return EINVAL;
}
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*))
{
uint32_t index;
taskENTER_CRITICAL();
for (index = 0; index < PTHREAD_KEY_MAX; index ++) {
if (_thread_keys[index].is_used == 0) {
_thread_keys[index].is_used = 1;
_thread_keys[index].destructor = destructor;
*key = index;
taskEXIT_CRITICAL();
return 0;
}
}
taskEXIT_CRITICAL();
return EAGAIN;
}
int pthread_key_delete(pthread_key_t key)
{
if (key >= PTHREAD_KEY_MAX)
return EINVAL;
taskENTER_CRITICAL();
_thread_keys[key].is_used = 0;
_thread_keys[key].destructor = 0;
taskEXIT_CRITICAL();
return 0;
}
int pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
{
taskENTER_CRITICAL();
if (!(*once_control))
{
/* call routine once */
*once_control = 1;
taskEXIT_CRITICAL();
if (init_routine)
init_routine();
return 0;
}
taskEXIT_CRITICAL();
return 0;
}
int pthread_once_ext(pthread_once_t *once_control, void (*init_routine)(void* arg), void* pargs)
{
taskENTER_CRITICAL();
if (!(*once_control))
{
/* call routine once */
*once_control = 1;
taskEXIT_CRITICAL();
if (init_routine)
init_routine(pargs);
return 0;
}
taskEXIT_CRITICAL();
return 0;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,167 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_pthread_barrier.c
* @brief Implementation of barrier functions in pthread.h
*/
/* C standard library includes. */
#include <stddef.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/pthread.h"
#include "atomic.h"
/*
* @brief barrier max count
*
* Barriers are implemented on FreeRTOS event groups, of which 8 bits are usable
* when configUSE_16_BIT_TICKS is 1. Otherwise, 24 bits are usable.
*/
/**@{ */
#if ( configUSE_16_BIT_TICKS == 1 )
#define posixPTHREAD_BARRIER_MAX_COUNT ( 8 )
#else
#define posixPTHREAD_BARRIER_MAX_COUNT ( 24 )
#endif
/**@} */
/*-----------------------------------------------------------*/
int pthread_barrier_destroy( pthread_barrier_t * barrier )
{
pthread_barrier_internal_t * pxBarrier = ( pthread_barrier_internal_t * ) ( barrier );
/* Free all resources used by the barrier. */
( void ) vEventGroupDelete( ( EventGroupHandle_t ) &pxBarrier->xBarrierEventGroup );
( void ) vSemaphoreDelete( ( SemaphoreHandle_t ) &pxBarrier->xThreadCountSemaphore );
return 0;
}
/*-----------------------------------------------------------*/
int pthread_barrier_init( pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr,
unsigned count )
{
int iStatus = 0;
pthread_barrier_internal_t * pxNewBarrier = ( pthread_barrier_internal_t * ) ( barrier );
/* Silence warnings about unused parameters. */
( void ) attr;
/* Ensure count is greater than 0. */
if( count == 0 )
{
iStatus = EINVAL;
}
/* Ensure that count will fit in a FreeRTOS event group. */
if( iStatus == 0 )
{
if( count > posixPTHREAD_BARRIER_MAX_COUNT )
{
/* No memory exists in the event group for more than
* posixPTHREAD_BARRIER_MAX_COUNT threads. */
iStatus = ENOMEM;
}
}
if( iStatus == 0 )
{
/* Set the current thread count and threshold. */
pxNewBarrier->uThreadCount = 0;
pxNewBarrier->uThreshold = count;
/* Create the FreeRTOS event group. This call will not fail when its
* argument isn't NULL. */
( void ) xEventGroupCreateStatic( &pxNewBarrier->xBarrierEventGroup );
/* Create the semaphore that prevents more than count threads from being
* unblocked by a single successful pthread_barrier_wait. This semaphore
* counts down from count and cannot decrement below 0. */
( void ) xSemaphoreCreateCountingStatic( ( UBaseType_t ) count, /* Max count. */
( UBaseType_t ) count, /* Initial count. */
&pxNewBarrier->xThreadCountSemaphore );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_barrier_wait( pthread_barrier_t * barrier )
{
int iStatus = 0;
unsigned i = 0; /* Loop iterator. */
pthread_barrier_internal_t * pxBarrier = ( pthread_barrier_internal_t * ) ( barrier );
unsigned uThreadNumber = 0;
/* Decrement the number of threads waiting on this barrier. This will prevent more
* than pxBarrier->uThreshold threads from being unblocked by a single successful
* pthread_barrier_wait call.
*
* This call will never fail because it blocks forever.
*/
( void ) xSemaphoreTake( ( SemaphoreHandle_t ) &pxBarrier->xThreadCountSemaphore, portMAX_DELAY );
uThreadNumber = Atomic_Increment_u32( ( uint32_t * ) &pxBarrier->uThreadCount );
/* Set the bit in the event group representing this thread, then wait for the other
* threads to set their bit. This call should wait forever until all threads have set
* their bit, so the return value is ignored. */
( void ) xEventGroupSync( ( EventGroupHandle_t ) &pxBarrier->xBarrierEventGroup,
1 << uThreadNumber, /* Which bit in the event group to set. */
( 1 << pxBarrier->uThreshold ) - 1, /* Wait for all threads to set their bits. */
portMAX_DELAY );
/* The first thread to enter the barrier gets PTHREAD_BARRIER_SERIAL_THREAD as its
* return value and resets xThreadCountSemaphore. */
if( uThreadNumber == 0 )
{
iStatus = PTHREAD_BARRIER_SERIAL_THREAD;
/* uThreadCount can be safely changed without locking xThreadCountMutex
* because xThreadCountSemaphore is currently 0. */
pxBarrier->uThreadCount = 0;
/* Reset xThreadCountSemaphore. This allows more threads to enter the
* barrier, starting a new cycle. */
for( i = 0; i < pxBarrier->uThreshold; i++ )
{
xSemaphoreGive( ( SemaphoreHandle_t ) &pxBarrier->xThreadCountSemaphore );
}
}
return iStatus;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,296 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_pthread_cond.c
* @brief Implementation of condition variable functions in pthread.h
*/
/* C standard library includes. */
#include <limits.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/pthread.h"
#include "FreeRTOS_POSIX/utils.h"
#include "atomic.h"
/**
* @brief Initialize a PTHREAD_COND_INITIALIZER cond.
*
* PTHREAD_COND_INITIALIZER sets a flag for a cond to be initialized later.
* This function performs the initialization.
* @param[in] pxCond The cond to initialize.
*
* @return nothing
*/
static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond );
/*-----------------------------------------------------------*/
static void prvInitializeStaticCond( pthread_cond_internal_t * pxCond )
{
/* Check if the condition variable needs to be initialized. */
if( pxCond->xIsInitialized == pdFALSE )
{
/* Cond initialization must be in a critical section to prevent two threads
* from initializing it at the same time. */
taskENTER_CRITICAL();
/* Check again that the cond is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if( pxCond->xIsInitialized == pdFALSE )
{
/* Set the members of the cond. The semaphore create calls will never fail
* when their arguments aren't NULL. */
pxCond->xIsInitialized = pdTRUE;
( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );
pxCond->iWaitingThreads = 0;
}
/* Exit the critical section. */
taskEXIT_CRITICAL();
}
}
/**
* @brief Check "atomically" if iLocalWaitingThreads == pxCond->iWaitingThreads and decrement.
*/
static void prvTestAndDecrement( pthread_cond_t * pxCond,
unsigned iLocalWaitingThreads )
{
/* Test local copy of threads waiting is larger than zero. */
while( iLocalWaitingThreads > 0 )
{
/* Test-and-set. Atomically check whether the copy in memory has changed.
* And, if not decrease the copy of threads waiting in memory. */
if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) )
{
/* Signal one succeeded. Break. */
break;
}
/* Local copy may be out dated. Reload, and retry. */
iLocalWaitingThreads = pxCond->iWaitingThreads;
}
}
/*-----------------------------------------------------------*/
int pthread_cond_broadcast( pthread_cond_t * cond )
{
unsigned i = 0;
pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
/* If the cond is uninitialized, perform initialization. */
prvInitializeStaticCond( pxCond );
/* Local copy of number of threads waiting. */
unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;
/* Test local copy of threads waiting is larger than zero. */
while( iLocalWaitingThreads > 0 )
{
/* Test-and-set. Atomically check whether the copy in memory has changed.
* And, if not set the copy of threads waiting in memory to zero. */
if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, 0, ( uint32_t ) iLocalWaitingThreads ) )
{
/* Unblock all. */
for( i = 0; i < iLocalWaitingThreads; i++ )
{
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
}
break;
}
/* Local copy is out dated. Reload, and retry. */
iLocalWaitingThreads = pxCond->iWaitingThreads;
}
return 0;
}
/*-----------------------------------------------------------*/
int pthread_cond_destroy( pthread_cond_t * cond )
{
pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
/* Free all resources in use by the cond. */
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
return 0;
}
/*-----------------------------------------------------------*/
int pthread_cond_init( pthread_cond_t * cond,
const pthread_condattr_t * attr )
{
int iStatus = 0;
pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) cond;
/* Silence warnings about unused parameters. */
( void ) attr;
if( pxCond == NULL )
{
iStatus = ENOMEM;
}
if( iStatus == 0 )
{
/* Set the members of the cond. The semaphore create calls will never fail
* when their arguments aren't NULL. */
pxCond->xIsInitialized = pdTRUE;
( void ) xSemaphoreCreateCountingStatic( INT_MAX, 0U, &pxCond->xCondWaitSemaphore );
pxCond->iWaitingThreads = 0;
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_cond_signal( pthread_cond_t * cond )
{
pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
/* If the cond is uninitialized, perform initialization. */
prvInitializeStaticCond( pxCond );
/* Local copy of number of threads waiting. */
unsigned iLocalWaitingThreads = pxCond->iWaitingThreads;
/* Test local copy of threads waiting is larger than zero. */
while( iLocalWaitingThreads > 0 )
{
/* Test-and-set. Atomically check whether the copy in memory has changed.
* And, if not decrease the copy of threads waiting in memory. */
if( ATOMIC_COMPARE_AND_SWAP_SUCCESS == Atomic_CompareAndSwap_u32( ( uint32_t * ) &pxCond->iWaitingThreads, ( uint32_t ) iLocalWaitingThreads - 1, ( uint32_t ) iLocalWaitingThreads ) )
{
/* Unblock one. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore );
/* Signal one succeeded. Break. */
break;
}
/* Local copy may be out dated. Reload, and retry. */
iLocalWaitingThreads = pxCond->iWaitingThreads;
}
return 0;
}
/*-----------------------------------------------------------*/
int pthread_cond_timedwait( pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec * abstime )
{
unsigned iLocalWaitingThreads;
int iStatus = 0;
pthread_cond_internal_t * pxCond = ( pthread_cond_internal_t * ) ( cond );
TickType_t xDelay = portMAX_DELAY;
/* If the cond is uninitialized, perform initialization. */
prvInitializeStaticCond( pxCond );
/* Convert abstime to a delay in TickType_t if provided. */
if( abstime != NULL )
{
struct timespec xCurrentTime = { 0 };
/* Get current time */
if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
{
iStatus = EINVAL;
}
else
{
iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
}
}
/* Increase the counter of threads blocking on condition variable, then
* unlock mutex. */
if( iStatus == 0 )
{
/* Atomically increments thread waiting by 1, and
* stores number of threads waiting before increment. */
iLocalWaitingThreads = Atomic_Increment_u32( ( uint32_t * ) &pxCond->iWaitingThreads );
iStatus = pthread_mutex_unlock( mutex );
}
/* Wait on the condition variable. */
if( iStatus == 0 )
{
if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxCond->xCondWaitSemaphore,
xDelay ) == pdPASS )
{
/* When successful, relock mutex. */
iStatus = pthread_mutex_lock( mutex );
}
else
{
/* Timeout. Relock mutex and decrement number of waiting threads. */
iStatus = ETIMEDOUT;
( void ) pthread_mutex_lock( mutex );
/* Atomically decrements thread waiting by 1.
* If iLocalWaitingThreads is updated by other thread(s) in between,
* this implementation guarantees to decrement by 1 based on the
* value currently in pxCond->iWaitingThreads. */
prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 );
}
}
else
{
/* Atomically decrements thread waiting by 1.
* If iLocalWaitingThreads is updated by other thread(s) in between,
* this implementation guarantees to decrement by 1 based on the
* value currently in pxCond->iWaitingThreads. */
prvTestAndDecrement( pxCond, iLocalWaitingThreads + 1 );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_cond_wait( pthread_cond_t * cond,
pthread_mutex_t * mutex )
{
return pthread_cond_timedwait( cond, mutex, NULL );
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,373 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_pthread_mutex.c
* @brief Implementation of mutex functions in pthread.h
*/
/* C standard library includes. */
#include <stddef.h>
#include <string.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/pthread.h"
#include "FreeRTOS_POSIX/utils.h"
/**
* @brief Initialize a PTHREAD_MUTEX_INITIALIZER mutex.
*
* PTHREAD_MUTEX_INITIALIZER sets a flag for a mutex to be initialized later.
* This function performs the initialization.
* @param[in] pxMutex The mutex to initialize.
*
* @return nothing
*/
static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex );
/**
* @brief Default pthread_mutexattr_t.
*/
static const pthread_mutexattr_internal_t xDefaultMutexAttributes =
{
.iType = PTHREAD_MUTEX_DEFAULT,
};
/*-----------------------------------------------------------*/
static void prvInitializeStaticMutex( pthread_mutex_internal_t * pxMutex )
{
/* Check if the mutex needs to be initialized. */
if( pxMutex->xIsInitialized == pdFALSE )
{
/* Mutex initialization must be in a critical section to prevent two threads
* from initializing it at the same time. */
taskENTER_CRITICAL();
/* Check again that the mutex is still uninitialized, i.e. it wasn't
* initialized while this function was waiting to enter the critical
* section. */
if( pxMutex->xIsInitialized == pdFALSE )
{
/* Set the mutex as the default type. */
pxMutex->xAttr.iType = PTHREAD_MUTEX_DEFAULT;
/* Call the correct FreeRTOS mutex initialization function based on
* the mutex type. */
#if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_RECURSIVE
( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex );
#else
( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex );
#endif
pxMutex->xIsInitialized = pdTRUE;
}
/* Exit the critical section. */
taskEXIT_CRITICAL();
}
}
/*-----------------------------------------------------------*/
int pthread_mutex_destroy( pthread_mutex_t * mutex )
{
pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );
/* Free resources in use by the mutex. */
if( pxMutex->xTaskOwner == NULL )
{
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxMutex->xMutex );
}
return 0;
}
/*-----------------------------------------------------------*/
int pthread_mutex_init( pthread_mutex_t * mutex,
const pthread_mutexattr_t * attr )
{
int iStatus = 0;
pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) mutex;
if( pxMutex == NULL )
{
/* No memory. */
iStatus = ENOMEM;
}
if( iStatus == 0 )
{
*pxMutex = FREERTOS_POSIX_MUTEX_INITIALIZER;
/* No attributes given, use default attributes. */
if( attr == NULL )
{
pxMutex->xAttr = xDefaultMutexAttributes;
}
/* Otherwise, use provided attributes. */
else
{
pxMutex->xAttr = *( ( pthread_mutexattr_internal_t * ) ( attr ) );
}
/* Call the correct FreeRTOS mutex creation function based on mutex type. */
if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )
{
/* Recursive mutex. */
( void ) xSemaphoreCreateRecursiveMutexStatic( &pxMutex->xMutex );
}
else
{
/* All other mutex types. */
( void ) xSemaphoreCreateMutexStatic( &pxMutex->xMutex );
}
/* Ensure that the FreeRTOS mutex was successfully created. */
if( ( SemaphoreHandle_t ) &pxMutex->xMutex == NULL )
{
/* Failed to create mutex. Set error EAGAIN and free mutex object. */
iStatus = EAGAIN;
vPortFree( pxMutex );
}
else
{
/* Mutex successfully created. */
pxMutex->xIsInitialized = pdTRUE;
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_mutex_lock( pthread_mutex_t * mutex )
{
return pthread_mutex_timedlock( mutex, NULL );
}
/*-----------------------------------------------------------*/
int pthread_mutex_timedlock( pthread_mutex_t * mutex,
const struct timespec * abstime )
{
int iStatus = 0;
pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );
TickType_t xDelay = portMAX_DELAY;
BaseType_t xFreeRTOSMutexTakeStatus = pdFALSE;
/* If mutex in uninitialized, perform initialization. */
prvInitializeStaticMutex( pxMutex );
/* At this point, the mutex should be initialized. */
configASSERT( pxMutex->xIsInitialized == pdTRUE );
/* Convert abstime to a delay in TickType_t if provided. */
if( abstime != NULL )
{
struct timespec xCurrentTime = { 0 };
/* Get current time */
if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
{
iStatus = EINVAL;
}
else
{
iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
}
/* If abstime was in the past, still attempt to lock the mutex without
* blocking, per POSIX spec. */
if( iStatus == ETIMEDOUT )
{
xDelay = 0;
iStatus = 0;
}
}
/* Check if trying to lock a currently owned mutex. */
if( ( iStatus == 0 ) &&
( pxMutex->xAttr.iType == PTHREAD_MUTEX_ERRORCHECK ) && /* Only PTHREAD_MUTEX_ERRORCHECK type detects deadlock. */
( pxMutex->xTaskOwner == xTaskGetCurrentTaskHandle() ) ) /* Check if locking a currently owned mutex. */
{
iStatus = EDEADLK;
}
if( iStatus == 0 )
{
/* Call the correct FreeRTOS mutex take function based on mutex type. */
if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )
{
xFreeRTOSMutexTakeStatus = xSemaphoreTakeRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay );
}
else
{
xFreeRTOSMutexTakeStatus = xSemaphoreTake( ( SemaphoreHandle_t ) &pxMutex->xMutex, xDelay );
}
/* If the mutex was successfully taken, set its owner. */
if( xFreeRTOSMutexTakeStatus == pdPASS )
{
pxMutex->xTaskOwner = xTaskGetCurrentTaskHandle();
}
/* Otherwise, the mutex take timed out. */
else
{
iStatus = ETIMEDOUT;
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_mutex_trylock( pthread_mutex_t * mutex )
{
int iStatus = 0;
struct timespec xTimeout =
{
.tv_sec = 0,
.tv_nsec = 0
};
/* Attempt to lock with no timeout. */
iStatus = pthread_mutex_timedlock( mutex, &xTimeout );
/* POSIX specifies that this function should return EBUSY instead of
* ETIMEDOUT for attempting to lock a locked mutex. */
if( iStatus == ETIMEDOUT )
{
iStatus = EBUSY;
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_mutex_unlock( pthread_mutex_t * mutex )
{
int iStatus = 0;
pthread_mutex_internal_t * pxMutex = ( pthread_mutex_internal_t * ) ( mutex );
/* If mutex in uninitialized, perform initialization. */
prvInitializeStaticMutex( pxMutex );
/* Check if trying to unlock an unowned mutex. */
if( ( ( pxMutex->xAttr.iType == PTHREAD_MUTEX_ERRORCHECK ) ||
( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE ) ) &&
( pxMutex->xTaskOwner != xTaskGetCurrentTaskHandle() ) )
{
iStatus = EPERM;
}
if( iStatus == 0 )
{
/* Suspend the scheduler so that
* mutex is unlocked AND owner is updated atomically */
vTaskSuspendAll();
/* Call the correct FreeRTOS mutex unlock function based on mutex type. */
if( pxMutex->xAttr.iType == PTHREAD_MUTEX_RECURSIVE )
{
( void ) xSemaphoreGiveRecursive( ( SemaphoreHandle_t ) &pxMutex->xMutex );
}
else
{
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxMutex->xMutex );
}
/* Update the owner of the mutex. A recursive mutex may still have an
* owner, so it should be updated with xSemaphoreGetMutexHolder. */
pxMutex->xTaskOwner = xSemaphoreGetMutexHolder( ( SemaphoreHandle_t ) &pxMutex->xMutex );
/* Resume the scheduler */
( void ) xTaskResumeAll();
}
return iStatus;
}
/*-----------------------------------------------------------*/
int pthread_mutexattr_destroy( pthread_mutexattr_t * attr )
{
( void ) attr;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr,
int * type )
{
pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr );
*type = pxAttr->iType;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_mutexattr_init( pthread_mutexattr_t * attr )
{
*( ( pthread_mutexattr_internal_t * ) ( attr ) ) = xDefaultMutexAttributes;
return 0;
}
/*-----------------------------------------------------------*/
int pthread_mutexattr_settype( pthread_mutexattr_t * attr,
int type )
{
int iStatus = 0;
pthread_mutexattr_internal_t * pxAttr = ( pthread_mutexattr_internal_t * ) ( attr );
switch( type )
{
case PTHREAD_MUTEX_NORMAL:
case PTHREAD_MUTEX_RECURSIVE:
case PTHREAD_MUTEX_ERRORCHECK:
pxAttr->iType = type;
break;
default:
iStatus = EINVAL;
break;
}
return iStatus;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,64 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_sched.c
* @brief Implementation of scheduler functions in sched.h
*/
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/sched.h"
/*-----------------------------------------------------------*/
int sched_get_priority_max( int policy )
{
/* Silence warnings about unused parameters. */
( void ) policy;
return configMAX_PRIORITIES - 1;
}
/*-----------------------------------------------------------*/
int sched_get_priority_min( int policy )
{
/* Silence warnings about unused parameters. */
( void ) policy;
return tskIDLE_PRIORITY;
}
/*-----------------------------------------------------------*/
int sched_yield( void )
{
taskYIELD();
return 0;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,232 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_semaphore.c
* @brief Implementation of functions in semaphore.h
*/
/* C standard library includes. */
#include <stddef.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/semaphore.h"
#include "FreeRTOS_POSIX/utils.h"
#include "atomic.h"
/*-----------------------------------------------------------*/
int sem_destroy( sem_t * sem )
{
sem_internal_t * pxSem = ( sem_internal_t * ) ( sem );
/* Free the resources in use by the semaphore. */
vSemaphoreDelete( ( SemaphoreHandle_t ) &pxSem->xSemaphore );
return 0;
}
/*-----------------------------------------------------------*/
int sem_getvalue( sem_t * sem,
int * sval )
{
sem_internal_t * pxSem = ( sem_internal_t * ) ( sem );
/* Get value does not need atomic operation, since -- Open Group
* states "the updated value represents an actual semaphore value that
* occurred at some unspecified time during the call, but it need not be the
* actual value of the semaphore when it is returned to the calling process."
*/
*sval = pxSem->value;
return 0;
}
/*-----------------------------------------------------------*/
int sem_init( sem_t * sem,
int pshared,
unsigned value )
{
int iStatus = 0;
sem_internal_t * pxSem = ( sem_internal_t * ) ( sem );
/* Silence warnings about unused parameters. */
( void ) pshared;
/* Check value parameter. */
if( value > SEM_VALUE_MAX )
{
errno = EINVAL;
iStatus = -1;
}
/* value is guaranteed to not exceed INT32_MAX, which is the default value of SEM_VALUE_MAX (0x7FFFU). */
pxSem->value = ( int ) value;
/* Create the FreeRTOS semaphore.
* This is only used to queue threads when no semaphore is available.
* Initializing with semaphore initial count zero.
* This call will not fail because the memory for the semaphore has already been allocated.
*/
if( iStatus == 0 )
{
( void ) xSemaphoreCreateCountingStatic( SEM_VALUE_MAX, 0, &pxSem->xSemaphore );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int sem_post( sem_t * sem )
{
sem_internal_t * pxSem = ( sem_internal_t * ) ( sem );
int iPreviouValue = Atomic_Increment_u32( ( uint32_t * ) &pxSem->value );
/* If previous semaphore value is equal or larger than zero, there is no
* thread waiting for this semaphore. Otherwise (<0), call FreeRTOS interface
* to wake up a thread. */
if( iPreviouValue < 0 )
{
/* Give the semaphore using the FreeRTOS API. */
( void ) xSemaphoreGive( ( SemaphoreHandle_t ) &pxSem->xSemaphore );
}
return 0;
}
/*-----------------------------------------------------------*/
int sem_timedwait( sem_t * sem,
const struct timespec * abstime )
{
int iStatus = 0;
sem_internal_t * pxSem = ( sem_internal_t * ) ( sem );
TickType_t xDelay = portMAX_DELAY;
int iPreviousValue = Atomic_Decrement_u32( ( uint32_t * ) &pxSem->value );
if( abstime != NULL )
{
/* If the provided timespec is invalid, still attempt to take the
* semaphore without blocking, per POSIX spec. */
if( UTILS_ValidateTimespec( abstime ) == false )
{
xDelay = 0;
iStatus = EINVAL;
}
else
{
struct timespec xCurrentTime = { 0 };
/* Get current time */
if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
{
iStatus = EINVAL;
}
else
{
iStatus = UTILS_AbsoluteTimespecToDeltaTicks( abstime, &xCurrentTime, &xDelay );
}
/* If abstime was in the past, still attempt to take the semaphore without
* blocking, per POSIX spec. */
if( iStatus == ETIMEDOUT )
{
xDelay = 0;
}
}
}
/* If previous semaphore value is larger than zero, the thread entering this function call
* can take the semaphore without yielding. Else (<=0), calling into FreeRTOS API to yield.
*/
if( iPreviousValue > 0 )
{
/* Under no circumstance shall the function fail with a timeout if the semaphore can be locked immediately. */
iStatus = 0;
}
else
{
/* Take the semaphore using the FreeRTOS API. */
if( xSemaphoreTake( ( SemaphoreHandle_t ) &pxSem->xSemaphore,
xDelay ) != pdTRUE )
{
if( iStatus == 0 )
{
errno = ETIMEDOUT;
}
else
{
errno = iStatus;
}
iStatus = -1;
}
else
{
iStatus = 0;
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int sem_trywait( sem_t * sem )
{
int iStatus = 0;
/* Setting an absolute timeout of 0 (i.e. in the past) will cause sem_timedwait
* to not block. */
struct timespec xTimeout = { 0 };
iStatus = sem_timedwait( sem, &xTimeout );
/* POSIX specifies that this function should set errno to EAGAIN and not
* ETIMEDOUT. */
if( ( iStatus == -1 ) && ( errno == ETIMEDOUT ) )
{
errno = EAGAIN;
}
return iStatus;
}
/*-----------------------------------------------------------*/
int sem_wait( sem_t * sem )
{
return sem_timedwait( sem, NULL );
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,337 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_timer.c
* @brief Implementation of timer functions in time.h
*/
/* C standard library includes. */
#include <stddef.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/pthread.h"
#include "FreeRTOS_POSIX/signal.h"
#include "FreeRTOS_POSIX/time.h"
#include "FreeRTOS_POSIX/utils.h"
/* FreeRTOS timer include. */
#include "timers.h"
/* Timespec zero check macros. */
#define TIMESPEC_IS_ZERO( xTimespec ) ( xTimespec.tv_sec == 0 && xTimespec.tv_nsec == 0 ) /**< Check for 0. */
#define TIMESPEC_IS_NOT_ZERO( xTimespec ) ( !( TIMESPEC_IS_ZERO( xTimespec ) ) ) /**< Check for not 0. */
/**
* @brief Internal timer structure.
*/
typedef struct timer_internal
{
StaticTimer_t xTimerBuffer; /**< Memory that holds the FreeRTOS timer. */
struct sigevent xTimerEvent; /**< What to do when this timer expires. */
TickType_t xTimerPeriod; /**< Period of this timer. */
} timer_internal_t;
/*-----------------------------------------------------------*/
void prvTimerCallback( TimerHandle_t xTimerHandle )
{
timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
pthread_t xTimerNotificationThread;
/* The value of the timer ID, set in timer_create, should not be NULL. */
configASSERT( pxTimer != NULL );
/* A value of SIGEV_SIGNAL isn't supported and should not have been successfully
* set. */
configASSERT( pxTimer->xTimerEvent.sigev_notify != SIGEV_SIGNAL );
/* Update the timer period, which may need to be set to an it_interval
* argument. This call should not block. */
if( pxTimer->xTimerPeriod > 0 )
{
xTimerChangePeriod( xTimerHandle, pxTimer->xTimerPeriod, 0 );
}
/* Create the timer notification thread if requested. */
if( pxTimer->xTimerEvent.sigev_notify == SIGEV_THREAD )
{
/* if the user has provided thread attributes, create a thread
* with the provided attributes. Otherwise dispatch callback directly */
if( pxTimer->xTimerEvent.sigev_notify_attributes == NULL )
{
( *pxTimer->xTimerEvent.sigev_notify_function )( pxTimer->xTimerEvent.sigev_value );
}
else
{
( void ) pthread_create( &xTimerNotificationThread,
pxTimer->xTimerEvent.sigev_notify_attributes,
( void * ( * )( void * ) )pxTimer->xTimerEvent.sigev_notify_function,
pxTimer->xTimerEvent.sigev_value.sival_ptr );
}
}
}
/*-----------------------------------------------------------*/
int timer_create( clockid_t clockid,
struct sigevent * evp,
timer_t * timerid )
{
int iStatus = 0;
timer_internal_t * pxTimer = NULL;
/* Silence warnings about unused parameters. */
( void ) clockid;
/* POSIX specifies that when evp is NULL, the behavior shall be as is
* sigev_notify is SIGEV_SIGNAL. SIGEV_SIGNAL is currently not supported. */
if( ( evp == NULL ) || ( evp->sigev_notify == SIGEV_SIGNAL ) )
{
errno = ENOTSUP;
iStatus = -1;
}
/* Allocate memory for a new timer object. */
if( iStatus == 0 )
{
pxTimer = pvPortMalloc( sizeof( timer_internal_t ) );
if( pxTimer == NULL )
{
errno = EAGAIN;
iStatus = -1;
}
}
if( iStatus == 0 )
{
/* Copy the event notification structure and set the current timer period. */
pxTimer->xTimerEvent = *evp;
pxTimer->xTimerPeriod = 0;
/* Create a new FreeRTOS timer. This call will not fail because the
* memory for it has already been allocated, so the output parameter is
* also set. */
*timerid = ( timer_t ) xTimerCreateStatic( posixconfigTIMER_NAME, /* Timer name. */
portMAX_DELAY, /* Initial timer period. Timers are created disarmed. */
pdFALSE, /* Don't auto-reload timer. */
( void * ) pxTimer, /* Timer id. */
prvTimerCallback, /* Timer expiration callback. */
&pxTimer->xTimerBuffer ); /* Pre-allocated memory for timer. */
}
return iStatus;
}
/*-----------------------------------------------------------*/
int timer_delete( timer_t timerid )
{
TimerHandle_t xTimerHandle = timerid;
timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
/* The value of the timer ID, set in timer_create, should not be NULL. */
configASSERT( pxTimer != NULL );
/* Stop the FreeRTOS timer. Because the timer is statically allocated, no call
* to xTimerDelete is necessary. The timer is stopped so that it's not referenced
* anywhere. xTimerStop will not fail when it has unlimited block time. */
( void ) xTimerStop( xTimerHandle, portMAX_DELAY );
/* Wait until the timer stop command is processed. */
while( xTimerIsTimerActive( xTimerHandle ) == pdTRUE )
{
vTaskDelay( 1 );
}
/* Free the memory in use by the timer. */
vPortFree( pxTimer );
return 0;
}
/*-----------------------------------------------------------*/
int timer_getoverrun( timer_t timerid )
{
/* Silence warnings about unused parameters. */
( void ) timerid;
return 0;
}
/*-----------------------------------------------------------*/
int timer_settime( timer_t timerid,
int flags,
const struct itimerspec * value,
struct itimerspec * ovalue )
{
int iStatus = 0;
TimerHandle_t xTimerHandle = timerid;
timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
TickType_t xNextTimerExpiration = 0, xTimerExpirationPeriod = 0;
BaseType_t xTimerCommandSent = pdFAIL;
/* Validate the value argument, but only if the timer isn't being disarmed. */
if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )
{
if( ( UTILS_ValidateTimespec( &value->it_interval ) == false ) ||
( UTILS_ValidateTimespec( &value->it_value ) == false ) )
{
errno = EINVAL;
iStatus = -1;
}
}
/* Set ovalue, if given. */
if( ovalue != NULL )
{
( void ) timer_gettime( timerid, ovalue );
}
/* Stop the timer if it's currently active. */
if( ( iStatus == 0 ) && xTimerIsTimerActive( xTimerHandle ) )
{
( void ) xTimerStop( xTimerHandle, portMAX_DELAY );
}
/* Only restart the timer if it_value is not zero. */
if( ( iStatus == 0 ) && TIMESPEC_IS_NOT_ZERO( value->it_value ) )
{
/* Convert it_interval to ticks, but only if it_interval is not 0. If
* it_interval is 0, then the timer is not periodic. */
if( TIMESPEC_IS_NOT_ZERO( value->it_interval ) )
{
( void ) UTILS_TimespecToTicks( &value->it_interval, &xTimerExpirationPeriod );
}
/* Set the new timer period. A non-periodic timer will have its period set
* to portMAX_DELAY. */
pxTimer->xTimerPeriod = xTimerExpirationPeriod;
/* Convert it_value to ticks, but only if it_value is not 0. If it_value
* is 0, then the timer will remain disarmed. */
if( TIMESPEC_IS_NOT_ZERO( value->it_value ) )
{
/* Absolute timeout. */
if( ( flags & TIMER_ABSTIME ) == TIMER_ABSTIME )
{
struct timespec xCurrentTime = { 0 };
/* Get current time */
if( clock_gettime( CLOCK_REALTIME, &xCurrentTime ) != 0 )
{
iStatus = EINVAL;
}
else
{
iStatus = UTILS_AbsoluteTimespecToDeltaTicks( &value->it_value, &xCurrentTime, &xNextTimerExpiration );
}
/* Make sure xNextTimerExpiration is zero in case we got negative time difference */
if( iStatus != 0 )
{
xNextTimerExpiration = 0;
if( iStatus == ETIMEDOUT )
{
/* Set Status to 0 as absolute time is past is treated as expiry but not an error */
iStatus = 0;
}
}
}
/* Relative timeout. */
else
{
( void ) UTILS_TimespecToTicks( &value->it_value, &xNextTimerExpiration );
}
}
/* If xNextTimerExpiration is still 0, that means that it_value specified
* an absolute timeout in the past. Per POSIX spec, a notification should be
* triggered immediately. */
if( xNextTimerExpiration == 0 )
{
prvTimerCallback( xTimerHandle );
}
else
{
/* Set the timer to expire at the it_value, then start it. */
( void ) xTimerChangePeriod( xTimerHandle, xNextTimerExpiration, portMAX_DELAY );
xTimerCommandSent = xTimerStart( xTimerHandle, xNextTimerExpiration );
/* Wait until the timer start command is processed. */
while( ( xTimerCommandSent != pdFAIL ) && ( xTimerIsTimerActive( xTimerHandle ) == pdFALSE ) )
{
vTaskDelay( 1 );
}
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int timer_gettime( timer_t timerid,
struct itimerspec * value )
{
TimerHandle_t xTimerHandle = timerid;
timer_internal_t * pxTimer = ( timer_internal_t * ) pvTimerGetTimerID( xTimerHandle );
TickType_t xNextExpirationTime = xTimerGetExpiryTime( xTimerHandle ) - xTaskGetTickCount(),
xTimerExpirationPeriod = pxTimer->xTimerPeriod;
/* Set it_value only if the timer is armed. Otherwise, set it to 0. */
if( xTimerIsTimerActive( xTimerHandle ) != pdFALSE )
{
value->it_value.tv_sec = ( time_t ) ( xNextExpirationTime / configTICK_RATE_HZ );
value->it_value.tv_nsec = ( long ) ( ( xNextExpirationTime % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK );
}
else
{
value->it_value.tv_sec = 0;
value->it_value.tv_nsec = 0;
}
/* Set it_interval only if the timer is periodic. Otherwise, set it to 0. */
if( xTimerExpirationPeriod != portMAX_DELAY )
{
value->it_interval.tv_sec = ( time_t ) ( xTimerExpirationPeriod / configTICK_RATE_HZ );
value->it_interval.tv_nsec = ( long ) ( ( xTimerExpirationPeriod % configTICK_RATE_HZ ) * NANOSECONDS_PER_TICK );
}
else
{
value->it_interval.tv_sec = 0;
value->it_interval.tv_nsec = 0;
}
return 0;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,62 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_unistd.c
* @brief Implementation of functions in unistd.h
*/
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/unistd.h"
/*-----------------------------------------------------------*/
unsigned sleep( unsigned seconds )
{
vTaskDelay( pdMS_TO_TICKS( seconds * 1000 ) );
return 0;
}
/*-----------------------------------------------------------*/
int usleep( useconds_t usec )
{
/* To avoid delaying for less than usec, always round up. */
vTaskDelay( pdMS_TO_TICKS( usec / 1000 + ( usec % 1000 != 0 ) ) );
return 0;
}
int msleep( useconds_t msec )
{
/* To avoid delaying for less than usec, always round up. */
vTaskDelay( pdMS_TO_TICKS( msec ) );
return 0;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,388 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_POSIX_utils.c
* @brief Implementation of utility functions in utils.h
*/
/* C standard library includes. */
#include <stddef.h>
#include <limits.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS_POSIX/errno.h"
#include "FreeRTOS_POSIX/utils.h"
/*-----------------------------------------------------------*/
size_t UTILS_strnlen( const char * const pcString,
size_t xMaxLength )
{
const char * pcCharPointer = pcString;
size_t xLength = 0;
if( pcString != NULL )
{
while( ( *pcCharPointer != '\0' ) && ( xLength < xMaxLength ) )
{
xLength++;
pcCharPointer++;
}
}
return xLength;
}
/*-----------------------------------------------------------*/
int UTILS_AbsoluteTimespecToDeltaTicks( const struct timespec * const pxAbsoluteTime,
const struct timespec * const pxCurrentTime,
TickType_t * const pxResult )
{
int iStatus = 0;
struct timespec xDifference = { 0 };
/* Check parameters. */
if( ( pxAbsoluteTime == NULL ) || ( pxCurrentTime == NULL ) || ( pxResult == NULL ) )
{
iStatus = EINVAL;
}
/* Calculate the difference between the current time and absolute time. */
if( iStatus == 0 )
{
iStatus = UTILS_TimespecSubtract( pxAbsoluteTime, pxCurrentTime, &xDifference );
if( iStatus == 1 )
{
/* pxAbsoluteTime was in the past. */
iStatus = ETIMEDOUT;
}
else if( iStatus == -1 )
{
/* error */
iStatus = EINVAL;
}
}
/* Convert the time difference to ticks. */
if( iStatus == 0 )
{
iStatus = UTILS_TimespecToTicks( &xDifference, pxResult );
}
return iStatus;
}
/*-----------------------------------------------------------*/
int UTILS_TimespecToTicks( const struct timespec * const pxTimespec,
TickType_t * const pxResult )
{
int iStatus = 0;
int64_t llTotalTicks = 0;
long lNanoseconds = 0;
/* Check parameters. */
if( ( pxTimespec == NULL ) || ( pxResult == NULL ) )
{
iStatus = EINVAL;
}
else if( ( iStatus == 0 ) && ( UTILS_ValidateTimespec( pxTimespec ) == false ) )
{
iStatus = EINVAL;
}
if( iStatus == 0 )
{
/* Convert timespec.tv_sec to ticks. */
llTotalTicks = ( int64_t ) configTICK_RATE_HZ * ( pxTimespec->tv_sec );
/* Convert timespec.tv_nsec to ticks. This value does not have to be checked
* for overflow because a valid timespec has 0 <= tv_nsec < 1000000000 and
* NANOSECONDS_PER_TICK > 1. */
lNanoseconds = pxTimespec->tv_nsec / ( long ) NANOSECONDS_PER_TICK + /* Whole nanoseconds. */
( long ) ( pxTimespec->tv_nsec % ( long ) NANOSECONDS_PER_TICK != 0 ); /* Add 1 to round up if needed. */
/* Add the nanoseconds to the total ticks. */
llTotalTicks += ( int64_t ) lNanoseconds;
/* Check for overflow */
if( llTotalTicks < 0 )
{
iStatus = EINVAL;
}
else
{
/* check if TickType_t is 32 bit or 64 bit */
uint32_t ulTickTypeSize = sizeof( TickType_t );
/* check for downcast overflow */
if( ulTickTypeSize == sizeof( uint32_t ) )
{
if( llTotalTicks > UINT_MAX )
{
iStatus = EINVAL;
}
}
}
/* Write result. */
*pxResult = ( TickType_t ) llTotalTicks;
}
return iStatus;
}
/*-----------------------------------------------------------*/
void UTILS_NanosecondsToTimespec( int64_t llSource,
struct timespec * const pxDestination )
{
long lCarrySec = 0;
/* Convert to timespec. */
pxDestination->tv_sec = ( time_t ) ( llSource / NANOSECONDS_PER_SECOND );
pxDestination->tv_nsec = ( long ) ( llSource % NANOSECONDS_PER_SECOND );
/* Subtract from tv_sec if tv_nsec < 0. */
if( pxDestination->tv_nsec < 0L )
{
/* Compute the number of seconds to carry. */
lCarrySec = ( pxDestination->tv_nsec / ( long ) NANOSECONDS_PER_SECOND ) + 1L;
pxDestination->tv_sec -= ( time_t ) ( lCarrySec );
pxDestination->tv_nsec += lCarrySec * ( long ) NANOSECONDS_PER_SECOND;
}
}
/*-----------------------------------------------------------*/
int UTILS_TimespecAdd( const struct timespec * const x,
const struct timespec * const y,
struct timespec * const pxResult )
{
int64_t llPartialSec = 0;
int iStatus = 0;
/* Check parameters. */
if( ( pxResult == NULL ) || ( x == NULL ) || ( y == NULL ) )
{
iStatus = -1;
}
if( iStatus == 0 )
{
/* Perform addition. */
pxResult->tv_nsec = x->tv_nsec + y->tv_nsec;
/* check for overflow in case nsec value was invalid */
if( pxResult->tv_nsec < 0 )
{
iStatus = 1;
}
else
{
llPartialSec = ( pxResult->tv_nsec ) / NANOSECONDS_PER_SECOND;
pxResult->tv_nsec = ( pxResult->tv_nsec ) % NANOSECONDS_PER_SECOND;
pxResult->tv_sec = x->tv_sec + y->tv_sec + llPartialSec;
/* check for overflow */
if( pxResult->tv_sec < 0 )
{
iStatus = 1;
}
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int UTILS_TimespecAddNanoseconds( const struct timespec * const x,
int64_t llNanoseconds,
struct timespec * const pxResult )
{
int64_t llTotalNSec = 0;
int iStatus = 0;
/* Check parameters. */
if( ( pxResult == NULL ) || ( x == NULL ) )
{
iStatus = -1;
}
if( iStatus == 0 )
{
/* add nano seconds */
llTotalNSec = x->tv_nsec + llNanoseconds;
/* check for nano seconds overflow */
if( llTotalNSec < 0 )
{
iStatus = 1;
}
else
{
pxResult->tv_nsec = llTotalNSec % NANOSECONDS_PER_SECOND;
pxResult->tv_sec = x->tv_sec + ( llTotalNSec / NANOSECONDS_PER_SECOND );
/* check for seconds overflow */
if( pxResult->tv_sec < 0 )
{
iStatus = 1;
}
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int UTILS_TimespecSubtract( const struct timespec * const x,
const struct timespec * const y,
struct timespec * const pxResult )
{
int iCompareResult = 0;
int iStatus = 0;
/* Check parameters. */
if( ( pxResult == NULL ) || ( x == NULL ) || ( y == NULL ) )
{
iStatus = -1;
}
if( iStatus == 0 )
{
iCompareResult = UTILS_TimespecCompare( x, y );
/* if x < y then result would be negative, return 1 */
if( iCompareResult == -1 )
{
iStatus = 1;
}
else if( iCompareResult == 0 )
{
/* if times are the same return zero */
pxResult->tv_sec = 0;
pxResult->tv_nsec = 0;
}
else
{
/* If x > y Perform subtraction. */
pxResult->tv_sec = x->tv_sec - y->tv_sec;
pxResult->tv_nsec = x->tv_nsec - y->tv_nsec;
/* check if nano seconds value needs to borrow */
if( pxResult->tv_nsec < 0 )
{
/* Based on comparison, tv_sec > 0 */
pxResult->tv_sec--;
pxResult->tv_nsec += ( long ) NANOSECONDS_PER_SECOND;
}
/* if nano second is negative after borrow, it is an overflow error */
if( pxResult->tv_nsec < 0 )
{
iStatus = -1;
}
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
int UTILS_TimespecCompare( const struct timespec * const x,
const struct timespec * const y )
{
int iStatus = 0;
/* Check parameters */
if( ( x == NULL ) && ( y == NULL ) )
{
iStatus = 0;
}
else if( y == NULL )
{
iStatus = 1;
}
else if( x == NULL )
{
iStatus = -1;
}
else if( x->tv_sec > y->tv_sec )
{
iStatus = 1;
}
else if( x->tv_sec < y->tv_sec )
{
iStatus = -1;
}
else
{
/* seconds are equal compare nano seconds */
if( x->tv_nsec > y->tv_nsec )
{
iStatus = 1;
}
else if( x->tv_nsec < y->tv_nsec )
{
iStatus = -1;
}
else
{
iStatus = 0;
}
}
return iStatus;
}
/*-----------------------------------------------------------*/
bool UTILS_ValidateTimespec( const struct timespec * const pxTimespec )
{
bool xReturn = false;
if( pxTimespec != NULL )
{
/* Verify 0 <= tv_nsec < 1000000000. */
if( ( pxTimespec->tv_nsec >= 0 ) &&
( pxTimespec->tv_nsec < NANOSECONDS_PER_SECOND ) )
{
xReturn = true;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,108 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file errno.h
* @brief System error numbers.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
*
* The values defined in this file may not be compatible with the strerror
* function provided by this system.
*/
#ifndef _FREERTOS_POSIX_ERRNO_H_
#define _FREERTOS_POSIX_ERRNO_H_
/* Undefine all errnos to avoid redefinition errors with system errnos. */
#undef EPERM
#undef ENOENT
#undef EBADF
#undef EAGAIN
#undef ENOMEM
#undef EEXIST
#undef EBUSY
#undef EINVAL
#undef ENOSPC
#undef ERANGE
#undef ENAMETOOLONG
#undef EDEADLK
#undef EOVERFLOW
#undef ENOSYS
#undef EMSGSIZE
#undef ENOTSUP
#undef ETIMEDOUT
/**
* @name Definition of POSIX errnos.
*/
/**@{ */
#define ENOERR 0 /**< No error */
#define EPERM 1 /**< Operation not permitted. */
#define ENOENT 2 /**< No such file or directory. */
#define ESRCH 3 /* No such process */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define EBADF 9 /**< Bad file descriptor. */
#define EAGAIN 11 /**< Resource unavailable, try again. */
#define ENOMEM 12 /**< Not enough space. */
#define EACCES 13 /* Permission denied */
#define EBUSY 16 /**< Device or resource busy. */
#define EEXIST 17 /**< File exists. */
#define ENODEV 19 /* No such device */
#define EINVAL 22 /**< Invalid argument. */
#define ENOSPC 28 /**< No space left on device. */
#define ERANGE 34 /**< Result too large. */
#define ENAMETOOLONG 36 /**< File name too long. */
#define EDEADLK 45 /**< Resource deadlock would occur. */
#define EPROTO 71 /* Protocol error */
#define EOVERFLOW 75 /**< Value too large to be stored in data type. */
#define EILSEQ 84 /* Illegal byte sequence */
#define ENOSYS 88 /**< Function not supported. */
#define EMSGSIZE 90 /**< Message too long. */
#define ENOTSUP 95 /**< Operation not supported. */
#define EINPROGRESS 115 /* Operation now in progress */
#define ETIMEDOUT 116 /**< Connection timed out. */
#define EREMOTEIO 121 /* Remote I/O error */
#define ENOMEDIUM 123 /* No medium found */
/**@} */
/**
* @name System Variable
*
* @brief Define FreeRTOS+POSIX errno, if enabled.
* Set configUSE_POSIX_ERRNO to enable, and clear to disable. See FreeRTOS.h.
*
* @{
*/
#if ( configUSE_POSIX_ERRNO == 1 )
extern int FreeRTOS_errno;
#define errno FreeRTOS_errno
#endif
/**@} */
#endif /* ifndef _FREERTOS_POSIX_ERRNO_H_ */

View File

@ -0,0 +1,79 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file fcntl.h
* @brief File control options.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fcntl.h.html
*/
#ifndef _FREERTOS_POSIX_FCNTL_H_
#define _FREERTOS_POSIX_FCNTL_H_
/**
* @name File creation flags for use in the oflag value to open() and openat().
*/
/**@{ */
#define O_CLOEXEC 0x0001 /**< Close the file descriptor upon exec(). */
#define O_CREAT 0x0002 /**< Create file if it does not exist. */
#define O_DIRECTORY 0x0004 /**< Fail if file is a non-directory file. */
#define O_EXCL 0x0008 /**< Exclusive use flag. */
#define O_NOCTTY 0x0010 /**< Do not assign controlling terminal. */
#define O_NOFOLLOW 0x0020 /**< Do not follow symbolic links. */
#define O_TRUNC 0x0040 /**< Truncate flag. */
#define O_TTY_INIT 0x0080 /**< termios structure provides conforming behavior. */
/**@} */
/**
* @name File status flags for open(), openat(), and fcntl().
*/
/**@{ */
#define O_APPEND 0x0100 /**< Set append mode. */
#define O_DSYNC 0x0200 /**< Write according to synchronized I/O data integrity completion. */
#define O_NONBLOCK 0x0400 /**< Non-blocking mode. */
#define O_RSYNC 0x0800 /**< Synchronized read I/O operations. */
#define O_SYNC 0x0200 /**< Write according to synchronized I/O file integrity completion. */
/**@} */
/**
* @name Mask for file access modes.
*/
/**@{ */
#define O_ACCMODE 0xF000
/**@} */
/**
* @name File access modes for open(), openat(), and fcntl().
*/
/**@{ */
#define O_EXEC 0x1000 /**< Open for execute only (non-directory files). */
#define O_RDONLY 0x2000 /**< Open for reading only. */
#define O_RDWR 0xA000 /**< Open for reading and writing. */
#define O_SEARCH 0x4000 /**< Open directory for search only. */
#define O_WRONLY 0x8000 /**< Open for writing only. */
/**@} */
#endif /* ifndef _FREERTOS_POSIX_FCNTL_H_ */

View File

@ -0,0 +1,250 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file mqueue.h
* @brief Message queues.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/mqueue.h.html
*/
#ifndef _FREERTOS_POSIX_MQUEUE_H_
#define _FREERTOS_POSIX_MQUEUE_H_
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX/time.h"
/**
* @brief Message queue descriptor.
*/
typedef void * mqd_t;
/**
* @brief Message queue attributes.
*/
struct mq_attr
{
long mq_flags; /**< Message queue flags. */
long mq_maxmsg; /**< Maximum number of messages. */
long mq_msgsize; /**< Maximum message size. */
long mq_curmsgs; /**< Number of messages currently queued. */
};
/**
* @brief Close a message queue.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_close.html
*
* @retval 0 - Upon successful completion
* @retval -1 - A error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EBADF - The mqdes argument is not a valid message queue descriptor.
*/
int mq_close( mqd_t mqdes );
/**
* @brief Get message queue attributes.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_getattr.html
*
* @retval 0 - Upon successful completion
* @retval -1 - A error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* DBADF - The mqdes argument is not a valid message queue descriptor.
*/
int mq_getattr( mqd_t mqdes,
struct mq_attr * mqstat );
/**
* @brief Open a message queue.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_open.html
*
* @note Supported name pattern: leading &lt;slash&gt; character in name is always required;
* the maximum length (excluding null-terminator) of the name argument can be NAME_MAX.
* The default value of NAME_MAX in FreeRTOS_POSIX_portable_default.h is 64, which can be
* overwritten by user.
* @note mode argument is not supported.
* @note Supported oflags: O_RDWR, O_CREAT, O_EXCL, and O_NONBLOCK.
*
* @retval Message queue descriptor -- Upon successful completion
* @retval (mqd_t) - 1 -- An error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EINVAL - name argument is invalid (not following name pattern),
* OR if O_CREAT is specified in oflag with attr argument not NULL and either mq_maxmsg or mq_msgsize is equal to or less than zero,
* OR either O_CREAT or O_EXCL is not set and a queue with the same name is unlinked but pending to be removed.
* <br>
* EEXIST - O_CREAT and O_EXCL are set and the named message queue already exists.
* <br>
* ENOSPC - There is insufficient space for the creation of the new message queue.
* <br>
* ENOENT - O_CREAT is not set and the named message queue does not exist.
*/
mqd_t mq_open( const char * name,
int oflag,
mode_t mode,
struct mq_attr * attr );
/**
* @brief Receive a message from a message queue.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_receive.html
*
* @note msg_prio argument is not supported. Messages are not checked for corruption.
*
* @retval The length of the selected message in bytes - Upon successful completion.
* The message is removed from the queue
* @retval -1 - An error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EBADF - The mqdes argument is not a valid message queue descriptor open for reading.
* <br>
* EMSGSIZE - The specified message buffer size, msg_len, is less than the message size attribute of the message queue.
* <br>
* ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened,
* but no message arrived on the queue before the specified timeout expired.
* <br>
* EAGAIN - O_NONBLOCK was set in the message description associated with mqdes, and the specified message queue is empty.
*/
ssize_t mq_receive( mqd_t mqdes,
char * msg_ptr,
size_t msg_len,
unsigned int * msg_prio );
/**
* @brief Send a message to a message queue.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_send.html
*
* @note msg_prio argument is not supported.
*
* @retval 0 - Upon successful completion.
* @retval -1 - An error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EBADF - The mqdes argument is not a valid message queue descriptor open for writing.
* <br>
* EMSGSIZE - The specified message length, msg_len, exceeds the message size attribute of the message queue,
* OR insufficient memory for the message to be sent.
* <br>
* ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened,
* but the timeout expired before the message could be added to the queue.
* <br>
* EAGAIN - The O_NONBLOCK flag is set in the message queue description associated with mqdes,
* and the specified message queue is full.
*/
int mq_send( mqd_t mqdes,
const char * msg_ptr,
size_t msg_len,
unsigned msg_prio );
/**
* @brief Receive a message from a message queue with timeout.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_timedreceive.html
*
* @note msg_prio argument is not supported. Messages are not checked for corruption.
*
* @retval The length of the selected message in bytes - Upon successful completion.
* The message is removed from the queue
* @retval -1 - An error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EBADF - The mqdes argument is not a valid message queue descriptor open for reading.
* <br>
* EMSGSIZE - The specified message buffer size, msg_len, is less than the message size attribute of the message queue.
* <br>
* EINVAL - The process or thread would have blocked, and the abstime parameter specified a nanoseconds field value
* less than zero or greater than or equal to 1000 million.
* <br>
* ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened,
* but no message arrived on the queue before the specified timeout expired.
* <br>
* EAGAIN - O_NONBLOCK was set in the message description associated with mqdes, and the specified message queue is empty.
*/
ssize_t mq_timedreceive( mqd_t mqdes,
char * msg_ptr,
size_t msg_len,
unsigned * msg_prio,
const struct timespec * abstime );
/**
* @brief Send a message to a message queue with timeout.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_timedsend.html
*
* @note msg_prio argument is not supported.
*
* @retval 0 - Upon successful completion.
* @retval -1 - An error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EBADF - The mqdes argument is not a valid message queue descriptor open for writing.
* <br>
* EMSGSIZE - The specified message length, msg_len, exceeds the message size attribute of the message queue,
* OR insufficient memory for the message to be sent.
* <br>
* EINVAL - The process or thread would have blocked, and the abstime parameter specified a nanoseconds field
* value less than zero or greater than or equal to 1000 million.
* <br>
* ETIMEDOUT - The O_NONBLOCK flag was not set when the message queue was opened,
* but the timeout expired before the message could be added to the queue.
* <br>
* EAGAIN - The O_NONBLOCK flag is set in the message queue description associated with mqdes,
* and the specified message queue is full.
*/
int mq_timedsend( mqd_t mqdes,
const char * msg_ptr,
size_t msg_len,
unsigned msg_prio,
const struct timespec * abstime );
/**
* @brief Remove a message queue.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_unlink.html
*
* @retval 0 - Upon successful completion.
* @retval -1 - An error occurred. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EINVAL - name argument is invalid. Refer to requirements on name argument in mq_open().
* <br>
* ENOENT - The named message queue does not exist.
*/
int mq_unlink( const char * name );
#endif /* ifndef _FREERTOS_POSIX_MQUEUE_H_ */

View File

@ -0,0 +1,513 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file pthread.h
* @brief Threads.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/pthread.h.html
*/
#ifndef _FREERTOS_POSIX_PTHREAD_H_
#define _FREERTOS_POSIX_PTHREAD_H_
/* FreeRTOS+POSIX includes. POSIX states that this header shall make symbols
* defined in sched.h and time.h visible. */
#include "FreeRTOS_POSIX/sched.h"
#include "FreeRTOS_POSIX/time.h"
/**
* @name pthread detach state.
*/
/**@{ */
#define PTHREAD_CREATE_DETACHED 0 /**< Detached. */
#define PTHREAD_CREATE_JOINABLE 1 /**< Joinable (default). */
/**@} */
/**
* @name Returned to a single thread after a successful pthread_barrier_wait.
*
* @brief POSIX specifies that "The constant PTHREAD_BARRIER_SERIAL_THREAD is defined in
* <pthread.h> and its value shall be distinct from any other value returned by pthread_barrier_wait()."
* So it's defined as negative to distinguish it from the errnos, which are positive.
*/
#define PTHREAD_BARRIER_SERIAL_THREAD ( -2 )
/**
* @name Mutex types.
*/
/**@{ */
#ifndef PTHREAD_MUTEX_NORMAL
#define PTHREAD_MUTEX_NORMAL 0 /**< Non-robust, deadlock on relock, does not remember owner. */
#endif
#ifndef PTHREAD_MUTEX_ERRORCHECK
#define PTHREAD_MUTEX_ERRORCHECK 1 /**< Non-robust, error on relock, remembers owner. */
#endif
#ifndef PTHREAD_MUTEX_RECURSIVE
#define PTHREAD_MUTEX_RECURSIVE 2 /**< Non-robust, recursive relock, remembers owner. */
#endif
#ifndef PTHREAD_MUTEX_DEFAULT
#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL /**< PTHREAD_MUTEX_NORMAL (default). */
#endif
/**@} */
/**
* @name Compile-time initializers.
*
* @brief To use PTHREAD_COND_INITIALIZER, posixconfigENABLE_PTHREAD_COND_T needs to be set to 1
* in port specific POSIX config file.
*
* To use PTHREAD_MUTEX_INITIALIZER, posixconfigENABLE_PTHREAD_MUTEX_T needs to be set to 1 in
* port specific POSIX config file.
*/
/**@{ */
#if posixconfigENABLE_PTHREAD_COND_T == 1
#define PTHREAD_COND_INITIALIZER FREERTOS_POSIX_COND_INITIALIZER /**< pthread_cond_t. */
#endif
#if posixconfigENABLE_PTHREAD_MUTEX_T == 1
#define PTHREAD_MUTEX_INITIALIZER FREERTOS_POSIX_MUTEX_INITIALIZER /**< pthread_mutex_t. */
#endif
/**@} */
/**
* @brief Destroy the thread attributes object.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_destroy.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_attr_destroy( pthread_attr_t * attr );
/**
* @brief Get detachstate attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getdetachstate.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_attr_getdetachstate( const pthread_attr_t * attr,
int * detachstate );
/**
* @brief Get schedparam attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getschedparam.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_attr_getschedparam( const pthread_attr_t * attr,
struct sched_param * param );
/**
* @brief Get stacksize attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_getstacksize.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_attr_getstacksize( const pthread_attr_t * attr,
size_t * stacksize );
/**
* @brief Initialize the thread attributes object.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_init.html
*
* @retval 0 - Upon successful completion.
*
* @note Currently, only stack size, sched_param, and detach state attributes
* are supported. Also see pthread_attr_get*() and pthread_attr_set*().
*/
int pthread_attr_init( pthread_attr_t * attr );
/**
* @brief Set detachstate attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setdetachstate.html
*
* @retval 0 - Upon successful completion
* @retval EINVAL - The value of detachstate is not valid. Currently, supported detach states are --
* PTHREAD_CREATE_DETACHED and PTHREAD_CREATE_JOINABLE.
*/
int pthread_attr_setdetachstate( pthread_attr_t * attr,
int detachstate );
/**
* @brief Set schedparam attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedparam.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The value of param is not valid.
* @retval ENOTSUP - An attempt was made to set the attribute to an unsupported value.
*/
int pthread_attr_setschedparam( pthread_attr_t * attr,
const struct sched_param * param );
/**
* @brief Set the schedpolicy attribute.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setschedpolicy.html
*
* @retval 0 - Upon successful completion.
*
* @warning This function is a stub and always returns 0.
*/
int pthread_attr_setschedpolicy( pthread_attr_t * attr,
int policy );
/**
* @brief Set stacksize attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_attr_setstacksize.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The value of stacksize is less than {PTHREAD_STACK_MIN}.
*/
int pthread_attr_setstacksize( pthread_attr_t * attr,
size_t stacksize );
/**
* @brief Destroy a barrier object.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_destroy.html
*
* @retval 0 - Upon successful completion.
*
* @note This function does not validate whether there is any thread blocking on the barrier before destroying.
*/
int pthread_barrier_destroy( pthread_barrier_t * barrier );
/**
* @brief Initialize a barrier object.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_init.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The value specified by count is equal to zero.
* @retval ENOMEM - count cannot fit into FreeRTOS event group type OR insufficient memory exists to initialize the barrier.
*
* @note attr is ignored.
*
* @note pthread_barrier_init() is implemented with FreeRTOS event group.
* To ensure count fits in event group, count may be at most 8 when configUSE_16_BIT_TICKS is 1;
* it may be at most 24 otherwise. configUSE_16_BIT_TICKS is configured in application FreeRTOSConfig.h
* file, which defines how many bits tick count type has. See further details and limitation about event
* group and configUSE_16_BIT_TICKS in FreeRTOS site.
*/
int pthread_barrier_init( pthread_barrier_t * barrier,
const pthread_barrierattr_t * attr,
unsigned count );
/**
* @brief Synchronize at a barrier.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_barrier_wait.html
*
* @retval PTHREAD_BARRIER_SERIAL_THREAD - Upon successful completion, the first thread.
* @retval 0 - Upon successful completion, other thread(s).
*/
int pthread_barrier_wait( pthread_barrier_t * barrier );
/**
* @brief Thread creation.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_create.html
*
* @retval 0 - Upon successful completion.
* @retval EAGAIN - Insufficient memory for either thread structure or task creation.
*/
int pthread_create( pthread_t * thread,
const pthread_attr_t * attr,
void *( *startroutine )( void * ),
void * arg );
/**
* @brief Broadcast a condition.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_cond_broadcast( pthread_cond_t * cond );
/**
* @brief Destroy condition variables.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_destroy.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_cond_destroy( pthread_cond_t * cond );
/**
* @brief Initialize condition variables.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html
*
* @retval 0 - Upon successful completion.
* @retval ENOMEM - Insufficient memory exists to initialize the condition variable.
*
* @note attr is ignored and treated as NULL. Default setting is always used.
*/
int pthread_cond_init( pthread_cond_t * cond,
const pthread_condattr_t * attr );
/**
* @brief Signal a condition.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_cond_signal( pthread_cond_t * cond );
/**
* @brief Wait on a condition with a timeout.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The abstime argument passed in does not refer to an initialized structure OR
* the abstime parameter specified a nanoseconds field value less than zero or
* greater than or equal to 1000 million.
* @retval ETIMEDOUT - The time specified by abstime to pthread_cond_timedwait() has passed.
*/
int pthread_cond_timedwait( pthread_cond_t * cond,
pthread_mutex_t * mutex,
const struct timespec * abstime );
/**
* @brief Wait on a condition.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_cond_wait( pthread_cond_t * cond,
pthread_mutex_t * mutex );
/**
* @brief Compare thread IDs.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_equal.html
*
* @retval 0 - t1 and t2 are both not NULL && equal.
* @retval non-zero - otherwise.
*/
int pthread_equal( pthread_t t1,
pthread_t t2 );
/**
* @brief Thread termination.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html
*
* @retval void - this function cannot return to its caller.
*/
void pthread_exit( void * value_ptr );
/**
* @brief Dynamic thread scheduling parameters access.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_getschedparam.html
*
* @retval 0 - Upon successful completion.
*
* @note policy is always set to SCHED_OTHER by this function.
*/
int pthread_getschedparam( pthread_t thread,
int * policy,
struct sched_param * param );
/**
* @brief Wait for thread termination.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_join.html
*
* @retval 0 - Upon successful completion.
* @retval EDEADLK - The value specified by the thread argument to pthread_join() does not refer
* to a joinable thread OR multiple simultaneous calls to pthread_join()
* specifying the same target thread OR the value specified by the thread argument
* to pthread_join() refers to the calling thread.
*/
int pthread_join( pthread_t thread,
void ** retval );
/**
* @brief Destroy a mutex.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_destroy.html
*
* @retval 0 - Upon successful completion.
*
* @note If there exists a thread holding this mutex, this function returns 0 with mutex not being destroyed.
*/
int pthread_mutex_destroy( pthread_mutex_t * mutex );
/**
* @brief Initialize a mutex.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html
*
* @retval 0 - Upon successful completion.
* @retval ENOMEM - Insufficient memory exists to initialize the mutex structure.
* @retval EAGAIN - Unable to initialize the mutex structure member(s).
*/
int pthread_mutex_init( pthread_mutex_t * mutex,
const pthread_mutexattr_t * attr );
/**
* @brief Lock a mutex.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - the abstime parameter specified a nanoseconds field value less than zero
* or greater than or equal to 1000 million.
* @retval EDEADLK - The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already
* owns the mutex.
*/
int pthread_mutex_lock( pthread_mutex_t * mutex );
/**
* @brief Lock a mutex with timeout.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_timedlock.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The abstime argument passed in does not refer to an initialized structure OR
* the abstime parameter specified a nanoseconds field value less than zero or
* greater than or equal to 1000 million.
* @retval EDEADLK - The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already owns the mutex.
* @retval ETIMEDOUT - The mutex could not be locked before the specified timeout expired.
*/
int pthread_mutex_timedlock( pthread_mutex_t * mutex,
const struct timespec * abstime );
/**
* @brief Attempt to lock a mutex. Fail immediately if mutex is already locked.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_trylock.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - the abstime parameter specified a nanoseconds field value less than zero
* or greater than or equal to 1000 million.
* @retval EDEADLK - The mutex type is PTHREAD_MUTEX_ERRORCHECK and the current thread already
* owns the mutex.
* @retval EBUSY - The mutex could not be acquired because it was already locked.
*/
int pthread_mutex_trylock( pthread_mutex_t * mutex );
/**
* @brief Unlock a mutex.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html
*
* @retval 0 - Upon successful completion.
* @retval EPERM - The mutex type is PTHREAD_MUTEX_ERRORCHECK or PTHREAD_MUTEX_RECURSIVE, and
* the current thread does not own the mutex.
*/
int pthread_mutex_unlock( pthread_mutex_t * mutex );
/**
* @brief Destroy the mutex attributes object.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_destroy.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_mutexattr_destroy( pthread_mutexattr_t * attr );
/**
* @brief Get the mutex type attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_gettype.html
*
* @retval 0 - Upon successful completion.
*/
int pthread_mutexattr_gettype( const pthread_mutexattr_t * attr,
int * type );
/**
* @brief Initialize the mutex attributes object.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_init.html
*
* @retval 0 - Upon successful completion.
*
* @note Currently, only the type attribute is supported. Also see pthread_mutexattr_settype()
* and pthread_mutexattr_gettype().
*/
int pthread_mutexattr_init( pthread_mutexattr_t * attr );
/**
* @brief Set the mutex type attribute.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutexattr_settype.html
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The value type is invalid.
*/
int pthread_mutexattr_settype( pthread_mutexattr_t * attr,
int type );
/**
* @brief Get the calling thread ID.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_self.html
*
* @retval the thread ID of the calling thread.
*/
pthread_t pthread_self( void );
/**
* @brief Dynamic thread scheduling parameters access.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_setschedparam.html
*
* @note policy is ignored; only priority (param.sched_priority) may be changed.
*
* @retval 0 - Upon successful completion.
*/
int pthread_setschedparam( pthread_t thread,
int policy,
const struct sched_param * param );
int pthread_key_create(pthread_key_t *, void (*)(void *));
int pthread_key_delete(pthread_key_t);
void *pthread_getspecific(pthread_key_t);
int pthread_setspecific(pthread_key_t, const void *);
#define PTHREAD_ONCE_INIT 0
int pthread_once(pthread_once_t * once_control, void (*init_routine) (void));
int pthread_once_ext(pthread_once_t *once_control, void (*init_routine)(void* arg), void* pargs);
#endif /* _FREERTOS_POSIX_PTHREAD_H_ */

View File

@ -0,0 +1,84 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file sched.h
* @brief Execution scheduling.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sched.h.html
*/
#ifndef _FREERTOS_POSIX_SCHED_H_
#define _FREERTOS_POSIX_SCHED_H_
/**
* @name Scheduling Policies
*/
/**@{ */
#define SCHED_OTHER 0 /**< Another scheduling policy. */
/**@} */
/**
* @brief Scheduling parameters required for implementation of each supported
* scheduling policy.
*/
struct sched_param
{
int sched_priority; /**< Process or thread execution scheduling priority. */
};
/**
* @brief Get priority limit (max).
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_max.html
*
* @note policy is ignored.
*
* @return the maximum priority value (0-based) system configuration allows.
* <br>
* e.g. if configMAX_PRIORITIES == 7, this function returns (configMAX_PRIORITIES - 1).
* configMAX_PRIORITIES is configured in application FreeRTOSConfig.h file.
*/
int sched_get_priority_max( int policy );
/**
* @brief Get priority limit (min).
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_get_priority_min.html
*
* @note policy is ignored.
*/
int sched_get_priority_min( int policy );
/**
* @brief Yield the processor.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/sched_yield.html
*
* @retval 0 - Upon successful completion
*/
int sched_yield( void );
#endif /* ifndef _FREERTOS_POSIX_SCHED_H_ */

View File

@ -0,0 +1,143 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file semaphore.h
* @brief Semaphores.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/semaphore.h.html
*/
#ifndef _FREERTOS_POSIX_SEMAPHORE_H_
#define _FREERTOS_POSIX_SEMAPHORE_H_
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX/time.h"
#include "FreeRTOS_POSIX_types.h"
/**
* @brief Semaphore type.
*/
typedef PosixSemType_t sem_t;
/**
* @brief Destroy an unnamed semaphore.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_destroy.html
*
* @retval 0 - upon successful completion
*
* @note Semaphore is destroyed regardless of whether there is any thread currently blocked on this semaphore.
*/
int sem_destroy( sem_t * sem );
/**
* @brief Get the value of a semaphore.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_getvalue.html
*
* @retval 0 - Upon successful completion
*
* @note If sem is locked, then the object to which sval points is set to zero.
*/
int sem_getvalue( sem_t * sem,
int * sval );
/**
* @brief Initialize an unnamed semaphore.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_init.html
*
* @note pshared is ignored. Semaphores will always be considered "shared".
*
* @retval 0 - upon successful completion
* @retval -1 - otherwise. System error variable errno is also set in this case.
*
* @sideeffect Possible errno values
* <br>
* EINVAL - The value argument exceeds {SEM_VALUE_MAX}.
* <br>
* ENOSPC - A resource required to initialize the semaphore has been exhausted.
*/
int sem_init( sem_t * sem,
int pshared,
unsigned value );
/**
* @brief Unlock a semaphore.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_post.html
*
* @retval 0 - upon successful completion
*/
int sem_post( sem_t * sem );
/**
* @brief Lock a semaphore with timeout.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_timedwait.html
*
* @retval 0 - upon successful completion
* @retval -1 - otherwise. System error variable errno is also set in this case.
*
* @sideeffect Possible errno values
* <br>
* EINVAL - parameter specified a nanoseconds field value less than zero or greater
* than or equal to 1000 million
* <br>
* ETIMEDOUT - The semaphore could not be locked before the specified timeout expired.
*
* @note Deadlock detection is not implemented.
*/
int sem_timedwait( sem_t * sem,
const struct timespec * abstime );
/**
* @brief Lock a semaphore if available.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_trywait.html
*
* @retval 0 - upon successful completion
* @retval -1 - otherwise. System error variable errno is also set in this case.
*
* @sideeffect Possible errno values
* <br>
* EAGAIN - The semaphore was already locked, so it cannot be immediately locked by the sem_trywait() operation.
*/
int sem_trywait( sem_t * sem );
/**
* @brief Lock a semaphore.
*
* @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/sem_wait.html
*
* @retval 0 - upon successful completion
* @retval -1 - otherwise. System error variable errno is also set in this case.
*
* @note Deadlock detection is not implemented.
*/
int sem_wait( sem_t * sem );
#endif /* ifndef _FREERTOS_POSIX_SEMAPHORE_H_ */

View File

@ -0,0 +1,70 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file signal.h
* @brief Signals.
*
* Signals are currently not implemented in FreeRTOS+POSIX. This header only
* defines the signal data structures used elsewhere.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html
*/
#ifndef _FREERTOS_POSIX_SIGNAL_H_
#define _FREERTOS_POSIX_SIGNAL_H_
/**
* @name Values of sigev_notify.
*/
/**@{ */
#define SIGEV_NONE 0 /**< No asynchronous notification is delivered when the event of interest occurs. */
#define SIGEV_SIGNAL 1 /**< A queued signal, with an application-defined value, is generated when the event of interest occurs. Not supported. */
#define SIGEV_THREAD 2 /**< A notification function is called to perform notification. */
/**@} */
/**
* @brief Signal value.
*/
union sigval
{
int sival_int; /**< Integer signal value. */
void * sival_ptr; /**< Pointer signal value. */
};
/**
* @brief Signal event structure.
*/
struct sigevent
{
int sigev_notify; /**< Notification type. A value of SIGEV_SIGNAL is not supported. */
int sigev_signo; /**< Signal number. This member is ignored. */
union sigval sigev_value; /**< Signal value. Only the sival_ptr member is used. */
void ( * sigev_notify_function )( union sigval ); /**< Notification function. */
pthread_attr_t * sigev_notify_attributes; /**< Notification attributes. */
};
#endif /* ifndef _FREERTOS_POSIX_SIGNAL_H_ */

View File

@ -0,0 +1,575 @@
/*
* Copyright (c) 1991, 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.
* 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.
*
* 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.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues, and circular queues.
*
* A singly-linked list is headed by a single forward pointer. The
* elements are singly linked for minimum space and pointer manipulation
* overhead at the expense of O(n) removal for arbitrary elements. New
* elements can be added to the list after an existing element or at the
* head of the list. Elements being removed from the head of the list
* should use the explicit macro for this purpose for optimum
* efficiency. A singly-linked list may only be traversed in the forward
* direction. Singly-linked lists are ideal for applications with large
* datasets and few or no removals or for implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* A circle queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the list.
* A circle queue may be traversed in either direction, but has a more
* complex end of list detection.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#define LIST_INIT(head) do { \
(head)->lh_first = NULL; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (/*CONSTCOND*/0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
} while (/*CONSTCOND*/0)
#define LIST_FOREACH(var, head, field) \
for ((var) = ((head)->lh_first); \
(var); \
(var) = ((var)->field.le_next))
/*
* List access methods.
*/
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) do { \
(head)->slh_first = NULL; \
} while (/*CONSTCOND*/0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (/*CONSTCOND*/0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (/*CONSTCOND*/0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = (head)->slh_first; \
while(curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
} \
} while (/*CONSTCOND*/0)
#define SLIST_FOREACH(var, head, field) \
for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next)
/*
* Singly-linked List access methods.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; /* first element */ \
struct type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_INIT(head) do { \
(head)->stqh_first = NULL; \
(head)->stqh_last = &(head)->stqh_first; \
} while (/*CONSTCOND*/0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
(head)->stqh_last = &(elm)->field.stqe_next; \
(head)->stqh_first = (elm); \
} while (/*CONSTCOND*/0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.stqe_next = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &(elm)->field.stqe_next; \
} while (/*CONSTCOND*/0)
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
(head)->stqh_last = &(elm)->field.stqe_next; \
(listelm)->field.stqe_next = (elm); \
} while (/*CONSTCOND*/0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
(head)->stqh_last = &(head)->stqh_first; \
} while (/*CONSTCOND*/0)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if ((head)->stqh_first == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->stqh_first; \
while (curelm->field.stqe_next != (elm)) \
curelm = curelm->field.stqe_next; \
if ((curelm->field.stqe_next = \
curelm->field.stqe_next->field.stqe_next) == NULL) \
(head)->stqh_last = &(curelm)->field.stqe_next; \
} \
} while (/*CONSTCOND*/0)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = ((head)->stqh_first); \
(var); \
(var) = ((var)->field.stqe_next))
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (/*CONSTCOND*/0)
/*
* Singly-linked Tail queue access methods.
*/
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
if ((head)->sqh_first == (elm)) { \
SIMPLEQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->sqh_first; \
while (curelm->field.sqe_next != (elm)) \
curelm = curelm->field.sqe_next; \
if ((curelm->field.sqe_next = \
curelm->field.sqe_next->field.sqe_next) == NULL) \
(head)->sqh_last = &(curelm)->field.sqe_next; \
} \
} while (/*CONSTCOND*/0)
#define SIMPLEQ_FOREACH(var, head, field) \
for ((var) = ((head)->sqh_first); \
(var); \
(var) = ((var)->field.sqe_next))
/*
* Simple queue access methods.
*/
#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL)
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
/*
* Tail queue definitions.
*/
#define _TAILQ_HEAD(name, type, qual) \
struct name { \
qual type *tqh_first; /* first element */ \
qual type *qual *tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define _TAILQ_ENTRY(type, qual) \
struct { \
qual type *tqe_next; /* next element */ \
qual type *qual *tqe_prev; /* address of previous next element */\
}
#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
} while (/*CONSTCOND*/0)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = ((head)->tqh_first); \
(var); \
(var) = ((var)->field.tqe_next))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \
(var); \
(var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (/*CONSTCOND*/0)
/*
* Tail queue access methods.
*/
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
/*
* Circular queue definitions.
*/
#define CIRCLEQ_HEAD(name, type) \
struct name { \
struct type *cqh_first; /* first element */ \
struct type *cqh_last; /* last element */ \
}
#define CIRCLEQ_HEAD_INITIALIZER(head) \
{ (void *)&head, (void *)&head }
#define CIRCLEQ_ENTRY(type) \
struct { \
struct type *cqe_next; /* next element */ \
struct type *cqe_prev; /* previous element */ \
}
/*
* Circular queue functions.
*/
#define CIRCLEQ_INIT(head) do { \
(head)->cqh_first = (void *)(head); \
(head)->cqh_last = (void *)(head); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm)->field.cqe_next; \
(elm)->field.cqe_prev = (listelm); \
if ((listelm)->field.cqe_next == (void *)(head)) \
(head)->cqh_last = (elm); \
else \
(listelm)->field.cqe_next->field.cqe_prev = (elm); \
(listelm)->field.cqe_next = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
(elm)->field.cqe_next = (listelm); \
(elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
if ((listelm)->field.cqe_prev == (void *)(head)) \
(head)->cqh_first = (elm); \
else \
(listelm)->field.cqe_prev->field.cqe_next = (elm); \
(listelm)->field.cqe_prev = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
(elm)->field.cqe_next = (head)->cqh_first; \
(elm)->field.cqe_prev = (void *)(head); \
if ((head)->cqh_last == (void *)(head)) \
(head)->cqh_last = (elm); \
else \
(head)->cqh_first->field.cqe_prev = (elm); \
(head)->cqh_first = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.cqe_next = (void *)(head); \
(elm)->field.cqe_prev = (head)->cqh_last; \
if ((head)->cqh_first == (void *)(head)) \
(head)->cqh_first = (elm); \
else \
(head)->cqh_last->field.cqe_next = (elm); \
(head)->cqh_last = (elm); \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_REMOVE(head, elm, field) do { \
if ((elm)->field.cqe_next == (void *)(head)) \
(head)->cqh_last = (elm)->field.cqe_prev; \
else \
(elm)->field.cqe_next->field.cqe_prev = \
(elm)->field.cqe_prev; \
if ((elm)->field.cqe_prev == (void *)(head)) \
(head)->cqh_first = (elm)->field.cqe_next; \
else \
(elm)->field.cqe_prev->field.cqe_next = \
(elm)->field.cqe_next; \
} while (/*CONSTCOND*/0)
#define CIRCLEQ_FOREACH(var, head, field) \
for ((var) = ((head)->cqh_first); \
(var) != (const void *)(head); \
(var) = ((var)->field.cqe_next))
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
for ((var) = ((head)->cqh_last); \
(var) != (const void *)(head); \
(var) = ((var)->field.cqe_prev))
/*
* Circular queue access methods.
*/
#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
#define CIRCLEQ_LOOP_NEXT(head, elm, field) \
(((elm)->field.cqe_next == (void *)(head)) \
? ((head)->cqh_first) \
: (elm->field.cqe_next))
#define CIRCLEQ_LOOP_PREV(head, elm, field) \
(((elm)->field.cqe_prev == (void *)(head)) \
? ((head)->cqh_last) \
: (elm->field.cqe_prev))
#endif /* sys/queue.h */

View File

@ -0,0 +1,7 @@
#ifndef _SYS_STAT_H
#define _SYS_STAT_H 1
#endif

View File

@ -0,0 +1,6 @@
#ifndef _SYS_TIME_H
#define _SYS_TIME_H 1
#include "FreeRTOS_POSIX/time.h"
#endif

View File

@ -0,0 +1,191 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file sys/types.h
* @brief Data types.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_types.h.html
*/
#ifndef _FREERTOS_POSIX_TYPES_H_
#define _FREERTOS_POSIX_TYPES_H_
/* C standard library includes. */
#include <stdint.h>
/* FreeRTOS types include */
#include "FreeRTOS_POSIX_types.h"
/**
* @brief Used for system times in clock ticks or CLOCKS_PER_SEC.
*
* Enabled/disabled by posixconfigENABLE_CLOCK_T.
*/
#if !defined( posixconfigENABLE_CLOCK_T ) || ( posixconfigENABLE_CLOCK_T == 1 )
typedef uint32_t clock_t;
#endif
/**
* @brief Used for clock ID type in the clock and timer functions.
*
* Enabled/disabled by posixconfigENABLE_CLOCKID_T.
*/
#if !defined( posixconfigENABLE_CLOCKID_T ) || ( posixconfigENABLE_CLOCKID_T == 1 )
typedef int clockid_t;
#endif
/**
* @brief Used for some file attributes.
*
* Enabled/disabled by posixconfigENABLE_MODE_T.
*/
#if !defined( posixconfigENABLE_MODE_T ) || ( posixconfigENABLE_MODE_T == 1 )
typedef int mode_t;
#endif
/**
* @brief Used for process IDs and process group IDs.
*
* Enabled/disabled by posixconfigENABLE_PID_T.
*/
#if !defined( posixconfigENABLE_PID_T ) || ( posixconfigENABLE_PID_T == 1 )
typedef int pid_t;
#endif
/**
* @brief Used to identify a thread attribute object.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_ATTR_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_ATTR_T ) || ( posixconfigENABLE_PTHREAD_ATTR_T == 1 )
typedef PthreadAttrType_t pthread_attr_t;
#endif
/**
* @brief Used to identify a barrier.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_BARRIER_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_BARRIER_T ) || ( posixconfigENABLE_PTHREAD_BARRIER_T == 1 )
typedef PthreadBarrierType_t pthread_barrier_t;
#endif
/**
* @brief Used to define a barrier attributes object.
*/
typedef void * pthread_barrierattr_t;
/**
* @brief Used for condition variables.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_COND_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_COND_T ) || ( posixconfigENABLE_PTHREAD_COND_T == 1 )
typedef PthreadCondType_t pthread_cond_t;
#endif
/**
* @brief Used to identify a condition attribute object.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_CONDATTR_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_CONDATTR_T ) || ( posixconfigENABLE_PTHREAD_CONDATTR_T == 1 )
typedef void * pthread_condattr_t;
#endif
/**
* @brief Used for mutexes.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_MUTEX_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_MUTEX_T ) || ( posixconfigENABLE_PTHREAD_MUTEX_T == 1 )
typedef PthreadMutexType_t pthread_mutex_t;
#endif
/**
* @brief Used to identify a mutex attribute object.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_MUTEXATTR_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_MUTEXATTR_T ) || ( posixconfigENABLE_PTHREAD_MUTEXATTR_T == 1 )
typedef PthreadMutexAttrType_t pthread_mutexattr_t;
#endif
/**
* @brief Used to identify a thread.
*
* Enabled/disabled by posixconfigENABLE_PTHREAD_T.
*/
#if !defined( posixconfigENABLE_PTHREAD_T ) || ( posixconfigENABLE_PTHREAD_T == 1 )
typedef void * pthread_t;
#endif
/**
* @brief Used for a count of bytes or an error indication.
*
* Enabled/disabled by posixconfigENABLE_SSIZE_T.
*/
#if !defined( posixconfigENABLE_SSIZE_T ) || ( posixconfigENABLE_SSIZE_T == 1 )
typedef int ssize_t;
#endif
/**
* @brief Used for time in seconds.
*
* Enabled/disabled by posixconfigENABLE_TIME_T.
*/
#if !defined( posixconfigENABLE_TIME_T ) || ( posixconfigENABLE_TIME_T == 1 )
typedef int64_t time_t;
#endif
/**
* @brief Used for timer ID returned by timer_create().
*
* Enabled/disabled by posixconfigENABLE_TIMER_T.
*/
#if !defined( posixconfigENABLE_TIMER_T ) || ( posixconfigENABLE_TIMER_T == 1 )
typedef void * timer_t;
#endif
/**
* @brief Used for time in microseconds.
*
* Enabled/disabled by posixconfigENABLE_USECONDS_T.
*/
#if !defined( posixconfigENABLE_USECONDS_T ) || ( posixconfigENABLE_USECONDS_T == 1 )
typedef unsigned long useconds_t;
#endif
/**
* @brief Used for file sizes.
*
* Enabled/disabled by posixconfigENABLE_OFF_T.
*/
#if !defined( posixconfigENABLE_OFF_T ) || ( posixconfigENABLE_OFF_T == 1 )
typedef long int off_t;
#endif
#endif /* ifndef _FREERTOS_POSIX_TYPES_H_ */

View File

@ -0,0 +1,5 @@
#ifndef _SYS_SYSLOG_H
#define _SYS_SYSLOG_H 1
#endif

View File

@ -0,0 +1,669 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file time.h
* @brief Time types.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html
*/
#ifndef _FREERTOS_POSIX_TIME_H_
#define _FREERTOS_POSIX_TIME_H_
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX/sys/types.h"
#include "FreeRTOS_POSIX/signal.h"
/**
* @name Unit conversion constants.
*/
/**@{ */
#define MICROSECONDS_PER_SECOND ( 1000000LL ) /**< Microseconds per second. */
#define NANOSECONDS_PER_SECOND ( 1000000000LL ) /**< Nanoseconds per second. */
#define NANOSECONDS_PER_TICK ( NANOSECONDS_PER_SECOND / configTICK_RATE_HZ ) /**< Nanoseconds per FreeRTOS tick. */
/**@} */
/**
* @name Clock identifiers.
*/
/**@{ */
#define CLOCK_REALTIME 0 /**< The identifier of the system-wide clock measuring real time. */
#define CLOCK_MONOTONIC 1 /**< The identifier for the system-wide monotonic clock.*/
/**@} */
/**
* @name A number used to convert the value returned by the clock() function into seconds.
*/
/**@{ */
#define CLOCKS_PER_SEC ( ( clock_t ) configTICK_RATE_HZ )
/**@} */
/**
* @name Flag indicating time is absolute.
*
* For functions taking timer objects, this refers to the clock associated with the timer.
*/
/**@{ */
#define TIMER_ABSTIME 0x01
/**@} */
#if !defined( posixconfigENABLE_TIMESPEC ) || ( posixconfigENABLE_TIMESPEC == 1 )
/**
* @brief represents an elapsed time
*/
struct timespec
{
time_t tv_sec; /**< Seconds. */
long tv_nsec; /**< Nanoseconds. */
};
#endif
#if !defined( posixconfigENABLE_ITIMERSPEC ) || ( posixconfigENABLE_ITIMERSPEC == 1 )
/**
* @brief timer
*/
struct itimerspec
{
struct timespec it_interval; /**< Timer period. */
struct timespec it_value; /**< Timer expiration. */
};
#endif
/**
* @brief Report CPU time used.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock.html
*
* @return The number of FreeRTOS ticks since the scheduler
* was started minus the ticks spent in the idle task.
*
* @note This function does NOT report the number of ticks spent by the calling thread.
*/
clock_t clock( void );
/**
* @brief Access a process CPU-time clock.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getcpuclockid.html
*
* @retval EPERM
*
* @note This function is currently unsupported.
*
*/
int clock_getcpuclockid( pid_t pid,
clockid_t * clock_id );
/**
* @brief Returns the resolution of a clock.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html
*
* @note clock_id is ignored
* @note This function stores the resolution of the FreeRTOS tick count in the object res points to.
*
* @retval 0 - Upon successful execution
*/
int clock_getres( clockid_t clock_id,
struct timespec * res );
/**
* @brief Returns the current value for the specified clock, clock_id.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_gettime.html
*
* @note clock_id is ignored
* @note this function does not check for overflows of time_t.
*
* @retval 0 - Upon successful completion.
*/
int clock_gettime( clockid_t clock_id,
struct timespec * tp );
/**
* @brief High resolution sleep with specifiable clock.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_nanosleep.html
*
* @note clock_id is ignored, as this function uses the FreeRTOS tick count as its clock.
* @note flags is ignored, if INCLUDE_vTaskDelayUntil is 0. i.e. the FreeRTOS function vTaskDelayUntil isn't available.
* @note rmtp is also ignored, as signals are not implemented.
*
* @retval 0 - Upon successful completion.
* @retval EINVAL - The rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million.
*/
int clock_nanosleep( clockid_t clock_id,
int flags,
const struct timespec * rqtp,
struct timespec * rmtp );
/**
* @brief Sets the time for the specified clock.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_settime.html
*
* @retval -1 with errno set to EPERM.
*
* @note This function is currently unsupported, as FreeRTOS does not provide a function to modify the tick count.
*/
int clock_settime( clockid_t clock_id,
const struct timespec * tp );
/**
* @brief High resolution sleep.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html
*
* @note rmtp is ignored, as signals are not implemented.
*
* @retval 0 - Upon successful completion.
* @retval -1 - The rqtp argument is invalid OR the rqtp argument specified a nanosecond value less than zero or greater than or equal to 1000 million.
*
*/
int nanosleep( const struct timespec * rqtp,
struct timespec * rmtp );
/**
* @brief Create a per-process timer.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_create.html
*
* @note clock_id is ignored, as this function used the FreeRTOS tick count as its clock.
* @note evp.sigev_notify must be set to SIGEV_THREAD, since signals are currently not supported.
*
* @retval 0 - Upon successful completion, with location referenced by timerid updated.
* @retval -1 - If an error occurs. errno is also set.
*
* @sideeffect Possible errno values
* <br>
* ENOTSUP - If evp is NULL OR evp->sigen_notify == SIGEV_SIGNAL.
* <br>
* EAGAIN - The system lacks sufficient signal queuing resources to honor the request.
*/
int timer_create( clockid_t clockid,
struct sigevent * evp,
timer_t * timerid );
/**
* @brief Delete a per-process timer.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_delete.html
*
* @retval 0 - Upon successful completion.
*/
int timer_delete( timer_t timerid );
/**
* @brief Get the timer overrun count.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_getoverrun.html
*
* @retval 0 - Always return 0, since signals are not supported.
*/
int timer_getoverrun( timer_t timerid );
/**
* @brief Get the amount of time until the timer expires.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_gettime.html
*
* @retval 0 - Upon successful completion.
*/
int timer_gettime( timer_t timerid,
struct itimerspec * value );
/**
* @brief Set the time until the next expiration of the timer.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/timer_settime.html
*
* @retval 0 - Upon successful completion.
* @retval -1 - An error occurred, errno is also set.
*
* @sideeffect Possible errno values
* <br>
* EINVAL - A value structure specified a nanosecond value less than zero or greater than or equal to 1000 million,
* AND the it_value member of that structure did not specify zero seconds and nanoseconds.
*/
int timer_settime( timer_t timerid,
int flags,
const struct itimerspec * value,
struct itimerspec * ovalue );
/**
The time function returns the systems current time stamp.
If timer is not a null pointer, the return value is also assigned to the object it points to.
*/
typedef int32_t __time32_t;
time_t time(time_t *timer);
time_t __time32(time_t *timer);
/**
The difftime function returns the difference between two binary time stamps,
time1 - time0.
*/
int32_t difftime(time_t time1, time_t time0);
int32_t __difftime32(time_t time1, time_t time0);
/**
The tm structure contains a representation of time 'broken down' into components of the
Gregorian calendar.
The normal ranges of the elements are..
\code
tm_sec seconds after the minute - [ 0 to 59 ]
tm_min minutes after the hour - [ 0 to 59 ]
tm_hour hours since midnight - [ 0 to 23 ]
tm_mday day of the month - [ 1 to 31 ]
tm_wday days since Sunday - [ 0 to 6 ]
tm_mon months since January - [ 0 to 11 ]
tm_year years since 1900
tm_yday days since January 1 - [ 0 to 365 ]
tm_isdst Daylight Saving Time flag *
\endcode
*The value of tm_isdst is zero if Daylight Saving Time is not in effect, and is negative if
the information is not available.
When Daylight Saving Time is in effect, the value represents the number of
seconds the clock is advanced.
See the set_dst() function for more information about Daylight Saving.
*/
typedef struct tm {
uint8_t tm_sec;
uint8_t tm_min;
uint8_t tm_hour;
uint8_t tm_mday;
uint8_t tm_wday;
uint8_t tm_mon;
uint16_t tm_year;
uint16_t tm_yday;
int16_t tm_isdst;
} tm;
/**
This function 'compiles' the elements of a broken-down time structure, returning a binary time stamp.
The elements of timeptr are interpreted as representing Local Time.
The original values of the tm_wday and tm_yday elements of the structure are ignored,
and the original values of the other elements are not restricted to the ranges stated for struct tm.
On successful completion, the values of all elements of timeptr are set to the appropriate range.
*/
time_t mktime(struct tm * timeptr);
time_t __mktime32(struct tm * timeptr);
/**
This function 'compiles' the elements of a broken-down time structure, returning a binary time stamp.
The elements of timeptr are interpreted as representing UTC.
The original values of the tm_wday and tm_yday elements of the structure are ignored,
and the original values of the other elements are not restricted to the ranges stated for struct tm.
Unlike mktime(), this function DOES NOT modify the elements of timeptr.
*/
time_t mk_gmtime(const struct tm * timeptr);
/**
The gmtime function converts the time stamp pointed to by timer into broken-down time,
expressed as UTC.
*/
struct tm *gmtime(const time_t * timer);
struct tm *__gmtime32(const time_t * timeptr);
/**
Re entrant version of gmtime().
*/
struct tm * gmtime_r(const time_t * timer, struct tm * timeptr);
/**
The localtime function converts the time stamp pointed to by timer into broken-down time,
expressed as Local time.
*/
struct tm *localtime(const time_t * timer);
struct tm *__localtime32(const time_t * timer);
/**
Re entrant version of localtime().
*/
struct tm *localtime_r(const time_t *timep, struct tm *result);
/**
The asctime function converts the broken-down time of timeptr, into an ascii string in the form
Sun Mar 23 01:03:52 2013
*/
char *asctime(const struct tm * timeptr);
/**
Re entrant version of asctime().
*/
//void asctime_r(const struct tm * timeptr, char *buffer);
char *asctime_r(const struct tm *timeptr, char *buffer);
/**
The ctime function is equivalent to asctime(localtime(timer))
*/
char *ctime(const time_t * timer);
char *__ctime32(const time_t * timeptr);
/**
Re entrant version of ctime().
*/
char *ctime_r(const time_t * timer, char *buf);
/**
The isotime function constructs an ascii string in the form
\code2013-03-23 01:03:52\endcode
*/
char *isotime(const struct tm * tmptr);
/**
Re entrant version of isotime()
*/
void isotime_r(const struct tm *, char *);
/**
A complete description of strftime() is beyond the pale of this document.
Refer to ISO/IEC document 9899 for details.
All conversions are made using the 'C Locale', ignoring the E or O modifiers. Due to the lack of
a time zone 'name', the 'Z' conversion is also ignored.
*/
size_t strftime(char *s, size_t maxsize, const char *format, const struct tm * timeptr);
/**
Specify the Daylight Saving function.
The Daylight Saving function should examine its parameters to determine whether
Daylight Saving is in effect, and return a value appropriate for tm_isdst.
Working examples for the USA and the EU are available..
\code #include <util/eu_dst.h>\endcode
for the European Union, and
\code #include <util/usa_dst.h>\endcode
for the United States
If a Daylight Saving function is not specified, the system will ignore Daylight Saving.
*/
void set_dst(int16_t (*) (const time_t *, int32_t *));
/**
Set the 'time zone'. The parameter is given in seconds East of the Prime Meridian.
Example for New York City:
\code set_zone(-5 * ONE_HOUR);\endcode
If the time zone is not set, the time system will operate in UTC only.
*/
void set_zone(int32_t);
/**
Initialize the system time. Examples are...
From a Clock / Calendar type RTC:
\code
struct tm rtc_time;
read_rtc(&rtc_time);
rtc_time.tm_isdst = 0;
set_system_time( mktime(&rtc_time) );
\endcode
From a Network Time Protocol time stamp:
\code
set_system_time(ntp_timestamp - NTP_OFFSET);
\endcode
From a UNIX time stamp:
\code
set_system_time(unix_timestamp - UNIX_OFFSET);
\endcode
*/
void set_system_time(time_t timestamp);
/**
Maintain the system time by calling this function at a rate of 1 Hertz.
It is anticipated that this function will typically be called from within an
Interrupt Service Routine, (though that is not required). It therefore includes code which
makes it simple to use from within a 'Naked' ISR, avoiding the cost of saving and restoring
all the cpu registers.
Such an ISR may resemble the following example...
\code
ISR(RTC_OVF_vect, ISR_NAKED)
{
system_tick();
reti();
}
\endcode
*/
void system_tick(void);
/**
Enumerated labels for the days of the week.
*/
enum _WEEK_DAYS_ {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
};
/**
Enumerated labels for the months.
*/
enum _MONTHS_ {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER
};
/**
Return 1 if year is a leap year, zero if it is not.
*/
//uint8_t is_leap_year(uint16_t year);
/**
Return the length of month, given the year and month, where month is in the range 1 to 12.
*/
uint8_t month_length(uint16_t year, uint8_t month);
/**
Return the calendar week of year, where week 1 is considered to begin on the
day of week specified by 'start'. The returned value may range from zero to 52.
*/
uint8_t week_of_year(const struct tm * timeptr, uint8_t start);
/**
Return the calendar week of month, where the first week is considered to begin on the
day of week specified by 'start'. The returned value may range from zero to 5.
*/
uint8_t week_of_month(const struct tm * timeptr, uint8_t start);
/**
Structure which represents a date as a year, week number of that year, and day of week.
See http://en.wikipedia.org/wiki/ISO_week_date for more information.
*/
struct week_date{
uint16_t year;
uint8_t week;
uint8_t day;
};
/**
Return a week_date structure with the ISO_8601 week based date corresponding to the given
year and day of year. See http://en.wikipedia.org/wiki/ISO_week_date for more
information.
*/
struct week_date * iso_week_date( uint16_t year, uint16_t yday);
/**
Re-entrant version of iso-week_date.
*/
void iso_week_date_r( uint16_t year, uint16_t yday, struct week_date *);
/**
Convert a Y2K time stamp into a FAT file system time stamp.
*/
uint32_t fatfs_time(const struct tm * timeptr);
/** One hour, expressed in seconds */
#define ONE_HOUR 3600
/** Angular degree, expressed in arc seconds */
#define ONE_DEGREE 3600
/** One day, expressed in seconds */
#define ONE_DAY 86400
/** Difference between the Y2K and the UNIX epochs, in seconds. To convert a Y2K
timestamp to UNIX...
\code
long unix;
time_t y2k;
y2k = time(NULL);
unix = y2k + UNIX_OFFSET;
\endcode
*/
#define UNIX_OFFSET 946684800
/** Difference between the Y2K and the NTP epochs, in seconds. To convert a Y2K
timestamp to NTP...
\code
unsigned long ntp;
time_t y2k;
y2k = time(NULL);
ntp = y2k + NTP_OFFSET;
\endcode
*/
#define NTP_OFFSET 3155673600
/*
* ===================================================================
* Ephemera
*/
/**
Set the geographic coordinates of the 'observer', for use with several of the
following functions. Parameters are passed as seconds of North Latitude, and seconds
of East Longitude.
For New York City...
\code set_position( 40.7142 * ONE_DEGREE, -74.0064 * ONE_DEGREE); \endcode
*/
void set_position(int32_t latitude, int32_t longitude);
/**
Computes the difference between apparent solar time and mean solar time.
The returned value is in seconds.
*/
int16_t equation_of_time(const time_t * timer);
/**
Computes the amount of time the sun is above the horizon, at the location of the observer.
NOTE: At observer locations inside a polar circle, this value can be zero during the winter,
and can exceed ONE_DAY during the summer.
The returned value is in seconds.
*/
int32_t daylight_seconds(const time_t * timer);
/**
Computes the time of solar noon, at the location of the observer.
*/
time_t solar_noon(const time_t * timer);
/**
Return the time of sunrise, at the location of the observer. See the note about daylight_seconds().
*/
time_t sun_rise(const time_t * timer);
/**
Return the time of sunset, at the location of the observer. See the note about daylight_seconds().
*/
time_t sun_set(const time_t * timer);
/** Returns the declination of the sun in radians. */
float solar_declination(const time_t * timer);
/**
Returns an approximation to the phase of the moon.
The sign of the returned value indicates a waning or waxing phase.
The magnitude of the returned value indicates the percentage illumination.
*/
int8_t moon_phase(const time_t * timer);
/**
Returns Greenwich Mean Sidereal Time, as seconds into the sidereal day.
The returned value will range from 0 through 86399 seconds.
*/
uint32_t gm_sidereal(const time_t * timer);
/**
Returns Local Mean Sidereal Time, as seconds into the sidereal day.
The returned value will range from 0 through 86399 seconds.
*/
uint32_t lm_sidereal(const time_t * timer);
int timespec_get(struct timespec *ts, int base);
int __timespec_get32(struct timespec *ts, int base);
//for c++ compile
#define EDOM 33
#endif /* ifndef _FREERTOS_POSIX_TIME_H_ */

View File

@ -0,0 +1,63 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file unistd.h
* @brief Standard symbolic constants and types
*
* http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html
*/
#ifndef _FREERTOS_POSIX_UNISTD_H_
#define _FREERTOS_POSIX_UNISTD_H_
#include "FreeRTOS_POSIX/sys/types.h"
/**
* @brief Suspend execution for an interval of time.
*
* http://pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html
*
* @param[in] seconds The number of seconds to suspend execution.
*
* @retval 0 - Upon successful completion.
*
* @note Return value of a positive number is not yet supported.
*/
unsigned sleep( unsigned seconds );
/**
* @brief Suspend execution for microsecond intervals.
*
* This is a useful, non-POSIX function.
* @param[in] usec The number of microseconds to suspend execution.
*
* @retval 0 - Upon successful completion.
*/
int usleep( useconds_t usec );
int msleep( useconds_t msec );
#endif /* ifndef _FREERTOS_POSIX_UNISTD_H_ */

View File

@ -0,0 +1,155 @@
/*
* Amazon FreeRTOS POSIX V1.1.0
* Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file utils.h
* @brief Utility functions used by FreeRTOS+POSIX.
*/
#ifndef _FREERTOS_POSIX_UTILS_
#define _FREERTOS_POSIX_UTILS_
/* C standard library includes. */
#include <stdbool.h>
#include <stdint.h>
/* FreeRTOS+POSIX includes. */
#include "FreeRTOS_POSIX/time.h"
/**
* @brief Calculates the length of pcString, up to xMaxLength.
*
* @param[in] pcString The string to find the length of.
* @param[in] xMaxLength The limit when searching for the end of pcString.
*
* @return 0 if pcString is NULL; otherwise, the length of pcString or xMaxLength,
* whichever is smaller.
*/
size_t UTILS_strnlen( const char * const pcString,
size_t xMaxLength );
/**
* @brief Calculates the number of ticks between now and a given timespec.
*
* @param[in] pxAbsoluteTime A time in the future, specified as seconds and
* nanoseconds since CLOCK_REALTIME's 0.
* @param[in] pxCurrentTime current time, specified as seconds and
* nanoseconds.
* @param[out] pxResult Where the result of the conversion is stored. The result
* is rounded up for fractional ticks.
*
* @return 0 on success. Otherwise, ETIMEDOUT if pxAbsoluteTime is in the past,
* or EINVAL for invalid parameters.
*/
int UTILS_AbsoluteTimespecToDeltaTicks( const struct timespec * const pxAbsoluteTime,
const struct timespec * const pxCurrentTime,
TickType_t * const pxResult );
/**
* @brief Converts a struct timespec to FreeRTOS ticks.
*
* @param[in] pxTimespec The timespec to convert.
* @param[out] Where the result of the conversion is stored. The result is rounded
* up for fractional ticks.
*
* @return 0 on success. Otherwise, EINVAL for invalid parameters.
*/
int UTILS_TimespecToTicks( const struct timespec * const pxTimespec,
TickType_t * const pxResult );
/**
* @brief Converts an integer value to a timespec.
*
* @param[in] llSource The value to convert.
* @param[out] pxDestination Where to store the converted value.
*
* @return No return value.
*/
void UTILS_NanosecondsToTimespec( int64_t llSource,
struct timespec * const pxDestination );
/**
* @brief Calculates pxResult = x + y.
*
* @param[in] x The first argument for addition.
* @param[in] y The second argument for addition.
* @param[out] pxResult Where the result of the calculation is stored.
*
* @return -1 if any argument was NULL; 1 if result is negative (overflow); otherwise, 0.
*/
int UTILS_TimespecAdd( const struct timespec * const x,
const struct timespec * const y,
struct timespec * const pxResult );
/**
* @brief Calculates pxResult = x + ( struct timespec ) nanosec.
*
* @param[in] x The first argument for addition.
* @param[in] llNanoseconds The second argument for addition.
* @param[out] pxResult Where the result of the calculation is stored.
*
* @return -1 if pxResult or x was NULL; 1 if result is negative; otherwise, 0.
*/
int UTILS_TimespecAddNanoseconds( const struct timespec * const x,
int64_t llNanoseconds,
struct timespec * const pxResult );
/**
* @brief Calculates pxResult = x - y. If the result is negative contents of
* pResult are undefined
*
* @param[in] x The first argument for subtraction.
* @param[in] y The second argument for subtraction.
* @param[out] pxResult Where the result of the calculation is stored.
*
* @return -1 if any argument was NULL; 1 if result is negative; otherwise, 0.
*/
int UTILS_TimespecSubtract( const struct timespec * const x,
const struct timespec * const y,
struct timespec * const pxResult );
/**
* @brief Compare x == y.
*
* @param[in] x The first argument for comparison.
* @param[in] y The second argument for comparison.
*
* @return 0 if x == y; 1 if x > y; -1 if x < y or any argument was NULL
*/
int UTILS_TimespecCompare( const struct timespec * const x,
const struct timespec * const y );
/**
* @brief Checks that a timespec conforms to POSIX.
*
* A valid timespec must have 0 <= tv_nsec < 1000000000.
*
* @param[in] pxTimespec The timespec to validate.
*
* @return true if the pxTimespec is valid, false otherwise.
*/
bool UTILS_ValidateTimespec( const struct timespec * const pxTimespec );
#endif /* ifndef _FREERTOS_POSIX_UTILS_ */

View File

@ -0,0 +1,242 @@
/*
* Amazon FreeRTOS Common V1.0.0
* Copyright (C) 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file iot_doubly_linked_list.h
* @brief Doubly Linked List implementation.
*
* A generic implementation of circular Doubly Linked List which consists of a
* list head and some list entries (zero in case of an empty list).
*
* To start with, a structure of type Link_t should be embedded in the structure
* which is to be organized as doubly linked list.
* @code
* typedef struct UserStruct
* {
* uint32_t ulField1;
* uint32_t ulField2;
* Link_t xLink;
* } UserStruct_t;
* @endcode
*
* A List head should then be defined and initialized.
* @code
* Link_t xListHead;
* listINIT_HEAD( &xListHead );
* @endcode
*
* listADD can then be used to add nodes to the list.
* @code
* listADD( &( xListHead ), &( pxUserStruct->xLink ) );
* @endcode
*
* listFOR_EACH can be used for traversing the list.
* @code
* Link_t *pxLink;
* UserStruct_t *pxUserStruct;
* listFOR_EACH( pxLink, &( xListHead ) )
* {
* pxUserStruct = listCONTAINER( pxLink, UserStruct_t, xLink );
* }
* @endcode
*
* listFOR_EACH_SAFE should be used if you want to perform destructive operations
* (like free) on nodes while traversing the list.
* @code
* Link_t *pxLink, *pxTempLink;
* UserStruct_t *pxUserStruct;
* listFOR_EACH( pxLink, pxTempLink, &( xListHead ) )
* {
* pxUserStruct = listCONTAINER( pxLink, UserStruct_t, xLink );
* free( pxUserStruct );
* }
* @endcode
*/
#ifndef _AWS_DOUBLY_LINKED_LIST_H_
#define _AWS_DOUBLY_LINKED_LIST_H_
#include <stddef.h>
#include <stdint.h>
/**
* @brief Struct embedded in any struct to make it a doubly linked
* list.
*
* pxNext in the head points to the first node in the list and pxPrev
* in the head points to the last node in the list. In case of empty
* list, both pxPrev and pxNext in the head point to the head node itself.
*/
typedef struct Link
{
struct Link * pxPrev; /**< Pointer to the previous node. */
struct Link * pxNext; /**< Pointer to the next node. */
} Link_t;
/**
* @brief Initializes the given list head to an empty list.
*
* @param[in] pxHead The given list head to initialize.
*/
#define listINIT_HEAD( pxHead ) \
{ \
( pxHead )->pxPrev = ( pxHead ); \
( pxHead )->pxNext = ( pxHead ); \
}
/**
* @brief Adds the given new node to the given list.
*
* @param[in] pxHead The head of the given list.
* @param[in] pxLink The given new node to be added to the given
* list.
*/
#define listADD( pxHead, pxLink ) \
{ \
Link_t * pxPrevLink = ( pxHead ); \
Link_t * pxNextLink = ( ( pxHead )->pxNext ); \
\
( pxLink )->pxNext = pxNextLink; \
pxNextLink->pxPrev = ( pxLink ); \
pxPrevLink->pxNext = ( pxLink ); \
( pxLink )->pxPrev = ( pxPrevLink ); \
}
/**
* @brief Removes the given node from the list it is part of.
*
* If the given node is not a part of any list (i.e. next and previous
* nodes are NULL), nothing happens.
*
* @param[in] pxLink The given node to remove from the list.
*/
#define listREMOVE( pxLink ) \
{ \
/* If the link is part of a list, remove it from the list. */ \
if( ( pxLink )->pxNext != NULL && ( pxLink )->pxPrev != NULL ) \
{ \
( pxLink )->pxPrev->pxNext = ( pxLink )->pxNext; \
( pxLink )->pxNext->pxPrev = ( pxLink )->pxPrev; \
} \
\
/* Make sure that this link is not part of any list anymore. */ \
( pxLink )->pxPrev = NULL; \
( pxLink )->pxNext = NULL; \
}
/**
* @brief Given the head of a list, checks if the list is empty.
*
* @param[in] pxHead The head of the given list.
*/
#define listIS_EMPTY( pxHead ) ( ( ( pxHead ) == NULL ) || ( ( pxHead )->pxNext == ( pxHead ) ) )
/**
* @brief Removes the first node from the given list and returns it.
*
* Removes the first node from the given list and assigns it to the
* pxLink parameter. If the list is empty, it assigns NULL to the
* pxLink.
*
* @param[in] pxHead The head of the list from which to remove the
* first node.
* @param[out] pxLink The output parameter to receive the removed
* node.
*/
#define listPOP( pxHead, pxLink ) \
{ \
if( listIS_EMPTY( ( pxHead ) ) ) \
{ \
( pxLink ) = NULL; \
} \
else \
{ \
( pxLink ) = ( pxHead )->pxNext; \
/* If the link is part of a list, remove it from the list. */ \
if( ( pxLink )->pxNext != NULL && ( pxLink )->pxPrev != NULL ) \
{ \
( pxLink )->pxPrev->pxNext = ( pxLink )->pxNext; \
( pxLink )->pxNext->pxPrev = ( pxLink )->pxPrev; \
} \
\
/* Make sure that this link is not part of any list anymore. */ \
( pxLink )->pxPrev = NULL; \
( pxLink )->pxNext = NULL; \
} \
}
/**
* @brief Merges a list into a given list.
*
* @param[in] pxHeadResultList The head of the given list into which the
* other list should be merged.
* @param[in] pxHeadListToMerge The head of the list to be merged into the
* given list.
*/
#define listMERGE( pxHeadResultList, pxHeadListToMerge ) \
{ \
if( !listIS_EMPTY( ( pxHeadListToMerge ) ) ) \
{ \
/* Setup links between last node of listToMerge and first node of resultList. */ \
( pxHeadListToMerge )->pxPrev->pxNext = ( pxHeadResultList )->pxNext; \
( pxHeadResultList )->pxNext->pxPrev = ( pxHeadListToMerge )->pxPrev; \
\
/* Setup links between first node of listToMerge and the head of resultList. */ \
( pxHeadListToMerge )->pxNext->pxPrev = ( pxHeadResultList ); \
( pxHeadResultList )->pxNext = ( pxHeadListToMerge )->pxNext; \
/* Empty the merged list. */ \
listINIT_HEAD( ( pxHeadListToMerge ) ); \
} \
}
/**
* @brief Helper macro to iterate over a list. pxLink contains the link node
* in each iteration.
*/
#define listFOR_EACH( pxLink, pxHead ) \
for( ( pxLink ) = ( pxHead )->pxNext; \
( pxLink ) != ( pxHead ); \
( pxLink ) = ( pxLink )->pxNext )
/**
* @brief Helper macro to iterate over a list. It is safe to destroy/free the
* nodes while iterating. pxLink contains the link node in each iteration.
*/
#define listFOR_EACH_SAFE( pxLink, pxTempLink, pxHead ) \
for( ( pxLink ) = ( pxHead )->pxNext, ( pxTempLink ) = ( pxLink )->pxNext; \
( pxLink ) != ( pxHead ); \
( pxLink ) = ( pxTempLink ), ( pxTempLink ) = ( pxLink )->pxNext )
/**
* @brief Given the pointer to the link member (of type Link_t) in a struct,
* extracts the pointer to the containing struct.
*
* @param[in] pxLink The pointer to the link member.
* @param[in] type The type of the containing struct.
* @param[in] member Name of the link member in the containing struct.
*/
#define listCONTAINER( pxLink, type, member ) ( ( type * ) ( ( uint8_t * ) ( pxLink ) - ( uint8_t * ) ( &( ( type * ) 0 )->member ) ) )
#endif /* _AWS_DOUBLY_LINKED_LIST_H_ */

View File

@ -0,0 +1,401 @@
/*
* FreeRTOS+TCP V2.3.2 LTS Patch 1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
/******************************************************************************
*
* See the following web page for essential buffer allocation scheme usage and
* configuration details:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Buffer_Management.html
*
******************************************************************************/
/* THIS FILE SHOULD NOT BE USED IF THE PROJECT INCLUDES A MEMORY ALLOCATOR
* THAT WILL FRAGMENT THE HEAP MEMORY. For example, heap_2 must not be used,
* heap_4 can be used. */
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
/* The obtained network buffer must be large enough to hold a packet that might
* replace the packet that was requested to be sent. */
#if ipconfigUSE_TCP == 1
#define baMINIMAL_BUFFER_SIZE sizeof( TCPPacket_t )
#else
#define baMINIMAL_BUFFER_SIZE sizeof( ARPPacket_t )
#endif /* ipconfigUSE_TCP == 1 */
/*_RB_ This is too complex not to have an explanation. */
#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
#define ASSERT_CONCAT_( a, b ) a ## b
#define ASSERT_CONCAT( a, b ) ASSERT_CONCAT_( a, b )
#define STATIC_ASSERT( e ) \
; enum { ASSERT_CONCAT( assert_line_, __LINE__ ) = 1 / ( !!( e ) ) }
STATIC_ASSERT( ipconfigETHERNET_MINIMUM_PACKET_BYTES <= baMINIMAL_BUFFER_SIZE );
#endif
/* A list of free (available) NetworkBufferDescriptor_t structures. */
static List_t xFreeBuffersList;
/* Some statistics about the use of buffers. */
static size_t uxMinimumFreeNetworkBuffers;
/* Declares the pool of NetworkBufferDescriptor_t structures that are available
* to the system. All the network buffers referenced from xFreeBuffersList exist
* in this array. The array is not accessed directly except during initialisation,
* when the xFreeBuffersList is filled (as all the buffers are free when the system
* is booted). */
static NetworkBufferDescriptor_t xNetworkBufferDescriptors[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ];
/* This constant is defined as false to let FreeRTOS_TCP_IP.c know that the
* network buffers have a variable size: resizing may be necessary */
const BaseType_t xBufferAllocFixedSize = pdFALSE;
/* The semaphore used to obtain network buffers. */
static SemaphoreHandle_t xNetworkBufferSemaphore = NULL;
/*-----------------------------------------------------------*/
BaseType_t xNetworkBuffersInitialise( void )
{
BaseType_t xReturn;
uint32_t x;
/* Only initialise the buffers and their associated kernel objects if they
* have not been initialised before. */
if( xNetworkBufferSemaphore == NULL )
{
xNetworkBufferSemaphore = xSemaphoreCreateCounting( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS );
configASSERT( xNetworkBufferSemaphore != NULL );
if( xNetworkBufferSemaphore != NULL )
{
#if ( configQUEUE_REGISTRY_SIZE > 0 )
{
vQueueAddToRegistry( xNetworkBufferSemaphore, "NetBufSem" );
}
#endif /* configQUEUE_REGISTRY_SIZE */
/* If the trace recorder code is included name the semaphore for viewing
* in FreeRTOS+Trace. */
#if ( ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 )
{
extern QueueHandle_t xNetworkEventQueue;
vTraceSetQueueName( xNetworkEventQueue, "IPStackEvent" );
vTraceSetQueueName( xNetworkBufferSemaphore, "NetworkBufferCount" );
}
#endif /* ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS == 1 */
vListInitialise( &xFreeBuffersList );
/* Initialise all the network buffers. No storage is allocated to
* the buffers yet. */
for( x = 0U; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ )
{
/* Initialise and set the owner of the buffer list items. */
xNetworkBufferDescriptors[ x ].pucEthernetBuffer = NULL;
vListInitialiseItem( &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
listSET_LIST_ITEM_OWNER( &( xNetworkBufferDescriptors[ x ].xBufferListItem ), &xNetworkBufferDescriptors[ x ] );
/* Currently, all buffers are available for use. */
vListInsert( &xFreeBuffersList, &( xNetworkBufferDescriptors[ x ].xBufferListItem ) );
}
uxMinimumFreeNetworkBuffers = ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS;
}
}
if( xNetworkBufferSemaphore == NULL )
{
xReturn = pdFAIL;
}
else
{
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
uint8_t * pucGetNetworkBuffer( size_t * pxRequestedSizeBytes )
{
uint8_t * pucEthernetBuffer;
size_t xSize = *pxRequestedSizeBytes;
if( xSize < baMINIMAL_BUFFER_SIZE )
{
/* Buffers must be at least large enough to hold a TCP-packet with
* headers, or an ARP packet, in case TCP is not included. */
xSize = baMINIMAL_BUFFER_SIZE;
}
/* Round up xSize to the nearest multiple of N bytes,
* where N equals 'sizeof( size_t )'. */
if( ( xSize & ( sizeof( size_t ) - 1U ) ) != 0U )
{
xSize = ( xSize | ( sizeof( size_t ) - 1U ) ) + 1U;
}
*pxRequestedSizeBytes = xSize;
/* Allocate a buffer large enough to store the requested Ethernet frame size
* and a pointer to a network buffer structure (hence the addition of
* ipBUFFER_PADDING bytes). */
pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xSize + ipBUFFER_PADDING );
configASSERT( pucEthernetBuffer != NULL );
if( pucEthernetBuffer != NULL )
{
/* Enough space is left at the start of the buffer to place a pointer to
* the network buffer structure that references this Ethernet buffer.
* Return a pointer to the start of the Ethernet buffer itself. */
pucEthernetBuffer += ipBUFFER_PADDING;
}
return pucEthernetBuffer;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBuffer( uint8_t * pucEthernetBuffer )
{
/* There is space before the Ethernet buffer in which a pointer to the
* network buffer that references this Ethernet buffer is stored. Remove the
* space before freeing the buffer. */
if( pucEthernetBuffer != NULL )
{
pucEthernetBuffer -= ipBUFFER_PADDING;
vPortFree( ( void * ) pucEthernetBuffer );
}
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t * pxGetNetworkBufferWithDescriptor( size_t xRequestedSizeBytes,
TickType_t xBlockTimeTicks )
{
NetworkBufferDescriptor_t * pxReturn = NULL;
size_t uxCount;
if( ( xRequestedSizeBytes <= ( ipconfigNETWORK_MTU + ipSIZE_OF_ETH_HEADER ) ) && ( xNetworkBufferSemaphore != NULL ) )
{
if( ( xRequestedSizeBytes != 0U ) && ( xRequestedSizeBytes < ( size_t ) baMINIMAL_BUFFER_SIZE ) )
{
/* ARP packets can replace application packets, so the storage must be
* at least large enough to hold an ARP. */
xRequestedSizeBytes = baMINIMAL_BUFFER_SIZE;
}
/* Add 2 bytes to xRequestedSizeBytes and round up xRequestedSizeBytes
* to the nearest multiple of N bytes, where N equals 'sizeof( size_t )'. */
xRequestedSizeBytes += 2U;
if( ( xRequestedSizeBytes & ( sizeof( size_t ) - 1U ) ) != 0U )
{
xRequestedSizeBytes = ( xRequestedSizeBytes | ( sizeof( size_t ) - 1U ) ) + 1U;
}
/* If there is a semaphore available, there is a network buffer available. */
if( xSemaphoreTake( xNetworkBufferSemaphore, xBlockTimeTicks ) == pdPASS )
{
/* Protect the structure as it is accessed from tasks and interrupts. */
taskENTER_CRITICAL();
{
pxReturn = ( NetworkBufferDescriptor_t * ) listGET_OWNER_OF_HEAD_ENTRY( &xFreeBuffersList );
( void ) uxListRemove( &( pxReturn->xBufferListItem ) );
}
taskEXIT_CRITICAL();
/* Reading UBaseType_t, no critical section needed. */
uxCount = listCURRENT_LIST_LENGTH( &xFreeBuffersList );
if( uxMinimumFreeNetworkBuffers > uxCount )
{
uxMinimumFreeNetworkBuffers = uxCount;
}
/* Allocate storage of exactly the requested size to the buffer. */
configASSERT( pxReturn->pucEthernetBuffer == NULL );
if( xRequestedSizeBytes > 0U )
{
/* Extra space is obtained so a pointer to the network buffer can
* be stored at the beginning of the buffer. */
pxReturn->pucEthernetBuffer = ( uint8_t * ) pvPortMalloc( xRequestedSizeBytes + ipBUFFER_PADDING );
if( pxReturn->pucEthernetBuffer == NULL )
{
/* The attempt to allocate storage for the buffer payload failed,
* so the network buffer structure cannot be used and must be
* released. */
vReleaseNetworkBufferAndDescriptor( pxReturn );
pxReturn = NULL;
}
else
{
/* Store a pointer to the network buffer structure in the
* buffer storage area, then move the buffer pointer on past the
* stored pointer so the pointer value is not overwritten by the
* application when the buffer is used. */
*( ( NetworkBufferDescriptor_t ** ) ( pxReturn->pucEthernetBuffer ) ) = pxReturn;
pxReturn->pucEthernetBuffer += ipBUFFER_PADDING;
/* Store the actual size of the allocated buffer, which may be
* greater than the original requested size. */
pxReturn->xDataLength = xRequestedSizeBytes;
#if ( ipconfigUSE_LINKED_RX_MESSAGES != 0 )
{
/* make sure the buffer is not linked */
pxReturn->pxNextBuffer = NULL;
}
#endif /* ipconfigUSE_LINKED_RX_MESSAGES */
}
}
else
{
/* A descriptor is being returned without an associated buffer being
* allocated. */
}
}
}
if( pxReturn == NULL )
{
iptraceFAILED_TO_OBTAIN_NETWORK_BUFFER();
}
else
{
/* No action. */
iptraceNETWORK_BUFFER_OBTAINED( pxReturn );
}
return pxReturn;
}
/*-----------------------------------------------------------*/
void vReleaseNetworkBufferAndDescriptor( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
BaseType_t xListItemAlreadyInFreeList;
/* Ensure the buffer is returned to the list of free buffers before the
* counting semaphore is 'given' to say a buffer is available. Release the
* storage allocated to the buffer payload. THIS FILE SHOULD NOT BE USED
* IF THE PROJECT INCLUDES A MEMORY ALLOCATOR THAT WILL FRAGMENT THE HEAP
* MEMORY. For example, heap_2 must not be used, heap_4 can be used. */
vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
pxNetworkBuffer->pucEthernetBuffer = NULL;
taskENTER_CRITICAL();
{
xListItemAlreadyInFreeList = listIS_CONTAINED_WITHIN( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
if( xListItemAlreadyInFreeList == pdFALSE )
{
vListInsertEnd( &xFreeBuffersList, &( pxNetworkBuffer->xBufferListItem ) );
}
}
taskEXIT_CRITICAL();
/*
* Update the network state machine, unless the program fails to release its 'xNetworkBufferSemaphore'.
* The program should only try to release its semaphore if 'xListItemAlreadyInFreeList' is false.
*/
if( xListItemAlreadyInFreeList == pdFALSE )
{
if( xSemaphoreGive( xNetworkBufferSemaphore ) == pdTRUE )
{
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
}
}
else
{
/* No action. */
iptraceNETWORK_BUFFER_RELEASED( pxNetworkBuffer );
}
}
/*-----------------------------------------------------------*/
/*
* Returns the number of free network buffers
*/
UBaseType_t uxGetNumberOfFreeNetworkBuffers( void )
{
return listCURRENT_LIST_LENGTH( &xFreeBuffersList );
}
/*-----------------------------------------------------------*/
UBaseType_t uxGetMinimumFreeNetworkBuffers( void )
{
return uxMinimumFreeNetworkBuffers;
}
/*-----------------------------------------------------------*/
NetworkBufferDescriptor_t * pxResizeNetworkBufferWithDescriptor( NetworkBufferDescriptor_t * pxNetworkBuffer,
size_t xNewSizeBytes )
{
size_t xOriginalLength;
uint8_t * pucBuffer;
xOriginalLength = pxNetworkBuffer->xDataLength + ipBUFFER_PADDING;
xNewSizeBytes = xNewSizeBytes + ipBUFFER_PADDING;
pucBuffer = pucGetNetworkBuffer( &( xNewSizeBytes ) );
if( pucBuffer == NULL )
{
/* In case the allocation fails, return NULL. */
pxNetworkBuffer = NULL;
}
else
{
pxNetworkBuffer->xDataLength = xNewSizeBytes;
if( xNewSizeBytes > xOriginalLength )
{
xNewSizeBytes = xOriginalLength;
}
( void ) memcpy( pucBuffer - ipBUFFER_PADDING, pxNetworkBuffer->pucEthernetBuffer - ipBUFFER_PADDING, xNewSizeBytes );
vReleaseNetworkBuffer( pxNetworkBuffer->pucEthernetBuffer );
pxNetworkBuffer->pucEthernetBuffer = pucBuffer;
}
return pxNetworkBuffer;
}

View File

@ -0,0 +1,951 @@
/*
* FreeRTOS+TCP V2.3.2 LTS Patch 1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_ARP.c
* @brief Implements the Address Resolution Protocol for the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_DHCP.h"
#if ( ipconfigUSE_LLMNR == 1 )
#include "FreeRTOS_DNS.h"
#endif /* ipconfigUSE_LLMNR */
#include "NetworkBufferManagement.h"
#include "NetworkInterface.h"
/** @brief When the age of an entry in the ARP table reaches this value (it counts down
* to zero, so this is an old entry) an ARP request will be sent to see if the
* entry is still valid and can therefore be refreshed. */
#define arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST ( 3 )
/** @brief The time between gratuitous ARPs. */
#ifndef arpGRATUITOUS_ARP_PERIOD
#define arpGRATUITOUS_ARP_PERIOD ( pdMS_TO_TICKS( 20000U ) )
#endif
/*-----------------------------------------------------------*/
/*
* Lookup an MAC address in the ARP cache from the IP address.
*/
static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
MACAddress_t * const pxMACAddress );
/*-----------------------------------------------------------*/
/** @brief The ARP cache. */
_static ARPCacheRow_t xARPCache[ ipconfigARP_CACHE_ENTRIES ];
/** @brief The time at which the last gratuitous ARP was sent. Gratuitous ARPs are used
* to ensure ARP tables are up to date and to detect IP address conflicts. */
static TickType_t xLastGratuitousARPTime = ( TickType_t ) 0;
/*
* IP-clash detection is currently only used internally. When DHCP doesn't respond, the
* driver can try out a random LinkLayer IP address (169.254.x.x). It will send out a
* gratuitous ARP message and, after a period of time, check the variables here below:
*/
#if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
/* Becomes non-zero if another device responded to a gratuitous ARP message. */
BaseType_t xARPHadIPClash;
/* MAC-address of the other device containing the same IP-address. */
MACAddress_t xARPClashMacAddress;
#endif /* ipconfigARP_USE_CLASH_DETECTION */
/*-----------------------------------------------------------*/
/**
* @brief Process the ARP packets.
*
* @param[in] pxARPFrame: The ARP Frame (the ARP packet).
*
* @return An enum which says whether to return the frame or to release it.
*/
eFrameProcessingResult_t eARPProcessPacket( ARPPacket_t * const pxARPFrame )
{
eFrameProcessingResult_t eReturn = eReleaseBuffer;
ARPHeader_t * pxARPHeader;
uint32_t ulTargetProtocolAddress, ulSenderProtocolAddress;
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
const void * pvCopySource;
void * pvCopyDest;
pxARPHeader = &( pxARPFrame->xARPHeader );
/* The field ulSenderProtocolAddress is badly aligned, copy byte-by-byte. */
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = pxARPHeader->ucSenderProtocolAddress;
pvCopyDest = &ulSenderProtocolAddress;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( ulSenderProtocolAddress ) );
/* The field ulTargetProtocolAddress is well-aligned, a 32-bits copy. */
ulTargetProtocolAddress = pxARPHeader->ulTargetProtocolAddress;
traceARP_PACKET_RECEIVED();
/* Don't do anything if the local IP address is zero because
* that means a DHCP request has not completed. */
if( *ipLOCAL_IP_ADDRESS_POINTER != 0UL )
{
switch( pxARPHeader->usOperation )
{
case ipARP_REQUEST://printf("%s:%d dst:%08x src:%08x\r\n", __func__, __LINE__, ulTargetProtocolAddress, *ipLOCAL_IP_ADDRESS_POINTER);
/* The packet contained an ARP request. Was it for the IP
* address of the node running this code? */
if( ulTargetProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
{
iptraceSENDING_ARP_REPLY( ulSenderProtocolAddress );
/* The request is for the address of this node. Add the
* entry into the ARP cache, or refresh the entry if it
* already exists. */
vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
/* Generate a reply payload in the same buffer. */
pxARPHeader->usOperation = ( uint16_t ) ipARP_REPLY;
if( ulTargetProtocolAddress == ulSenderProtocolAddress )
{
/* A double IP address is detected! */
/* Give the sources MAC address the value of the broadcast address, will be swapped later */
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = xBroadcastMACAddress.ucBytes;
pvCopyDest = pxARPFrame->xEthernetHeader.xSourceAddress.ucBytes;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xBroadcastMACAddress ) );
( void ) memset( pxARPHeader->xTargetHardwareAddress.ucBytes, 0, sizeof( MACAddress_t ) );
pxARPHeader->ulTargetProtocolAddress = 0UL;
}
else
{
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = pxARPHeader->xSenderHardwareAddress.ucBytes;
pvCopyDest = pxARPHeader->xTargetHardwareAddress.ucBytes;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
pxARPHeader->ulTargetProtocolAddress = ulSenderProtocolAddress;
}
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = ipLOCAL_MAC_ADDRESS;
pvCopyDest = pxARPHeader->xSenderHardwareAddress.ucBytes;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( MACAddress_t ) );
pvCopySource = ipLOCAL_IP_ADDRESS_POINTER;
pvCopyDest = pxARPHeader->ucSenderProtocolAddress;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPHeader->ucSenderProtocolAddress ) );
eReturn = eReturnEthernetFrame;
}
break;
case ipARP_REPLY:printf("%s:%d \r\n", __func__, __LINE__);
iptracePROCESSING_RECEIVED_ARP_REPLY( ulTargetProtocolAddress );
vARPRefreshCacheEntry( &( pxARPHeader->xSenderHardwareAddress ), ulSenderProtocolAddress );
/* Process received ARP frame to see if there is a clash. */
#if ( ipconfigARP_USE_CLASH_DETECTION != 0 )
{
if( ulSenderProtocolAddress == *ipLOCAL_IP_ADDRESS_POINTER )
{
xARPHadIPClash = pdTRUE;
/* Remember the MAC-address of the other device which has the same IP-address. */
( void ) memcpy( xARPClashMacAddress.ucBytes, pxARPHeader->xSenderHardwareAddress.ucBytes, sizeof( xARPClashMacAddress.ucBytes ) );
}
}
#endif /* ipconfigARP_USE_CLASH_DETECTION */
break;
default:
/* Invalid. */
break;
}
}
return eReturn;
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_ARP_REMOVE_ENTRY != 0 )
/**
* @brief Remove an ARP cache entry that matches with .pxMACAddress.
*
* @param[in] pxMACAddress: Pointer to the MAC address whose entry shall
* be removed..
* @return When the entry was found and remove: the IP-address, otherwise zero.
*/
uint32_t ulARPRemoveCacheEntryByMac( const MACAddress_t * pxMACAddress )
{
BaseType_t x;
uint32_t lResult = 0;
configASSERT( pxMACAddress != NULL );
/* For each entry in the ARP cache table. */
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
{
if( ( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 ) )
{
lResult = xARPCache[ x ].ulIPAddress;
( void ) memset( &xARPCache[ x ], 0, sizeof( xARPCache[ x ] ) );
break;
}
}
return lResult;
}
#endif /* ipconfigUSE_ARP_REMOVE_ENTRY != 0 */
/*-----------------------------------------------------------*/
/**
* @brief Add/update the ARP cache entry MAC-address to IP-address mapping.
*
* @param[in] pxMACAddress: Pointer to the MAC address whose mapping is being
* updated.
* @param[in] ulIPAddress: 32-bit representation of the IP-address whose mapping
* is being updated.
*/
void vARPRefreshCacheEntry( const MACAddress_t * pxMACAddress,
const uint32_t ulIPAddress )
{
BaseType_t x = 0;
BaseType_t xIpEntry = -1;
BaseType_t xMacEntry = -1;
BaseType_t xUseEntry = 0;
uint8_t ucMinAgeFound = 0U;
#if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 0 )
/* Only process the IP address if it is on the local network.
* Unless: when '*ipLOCAL_IP_ADDRESS_POINTER' equals zero, the IP-address
* and netmask are still unknown. */
if( ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) ) ||
( *ipLOCAL_IP_ADDRESS_POINTER == 0UL ) )
#else
/* If ipconfigARP_STORES_REMOTE_ADDRESSES is non-zero, IP addresses with
* a different netmask will also be stored. After when replying to a UDP
* message from a different netmask, the IP address can be looped up and a
* reply sent. This option is useful for systems with multiple gateways,
* the reply will surely arrive. If ipconfigARP_STORES_REMOTE_ADDRESSES is
* zero the the gateway address is the only option. */
if( pdTRUE )
#endif
{
/* Start with the maximum possible number. */
ucMinAgeFound--;
/* For each entry in the ARP cache table. */
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
{
BaseType_t xMatchingMAC;
if( pxMACAddress != NULL )
{
if( memcmp( xARPCache[ x ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) ) == 0 )
{
xMatchingMAC = pdTRUE;
}
else
{
xMatchingMAC = pdFALSE;
}
}
else
{
xMatchingMAC = pdFALSE;
}
/* Does this line in the cache table hold an entry for the IP
* address being queried? */
if( xARPCache[ x ].ulIPAddress == ulIPAddress )
{
if( pxMACAddress == NULL )
{
/* In case the parameter pxMACAddress is NULL, an entry will be reserved to
* indicate that there is an outstanding ARP request, This entry will have
* "ucValid == pdFALSE". */
xIpEntry = x;
break;
}
/* See if the MAC-address also matches. */
if( xMatchingMAC != pdFALSE )
{
/* This function will be called for each received packet
* As this is by far the most common path the coding standard
* is relaxed in this case and a return is permitted as an
* optimisation. */
xARPCache[ x ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
xARPCache[ x ].ucValid = ( uint8_t ) pdTRUE;
return;
}
/* Found an entry containing ulIPAddress, but the MAC address
* doesn't match. Might be an entry with ucValid=pdFALSE, waiting
* for an ARP reply. Still want to see if there is match with the
* given MAC address.ucBytes. If found, either of the two entries
* must be cleared. */
xIpEntry = x;
}
else if( xMatchingMAC != pdFALSE )
{
/* Found an entry with the given MAC-address, but the IP-address
* is different. Continue looping to find a possible match with
* ulIPAddress. */
#if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 )
/* If ARP stores the MAC address of IP addresses outside the
* network, than the MAC address of the gateway should not be
* overwritten. */
BaseType_t bIsLocal[ 2 ];
bIsLocal[ 0 ] = ( ( xARPCache[ x ].ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
bIsLocal[ 1 ] = ( ( ulIPAddress & xNetworkAddressing.ulNetMask ) == ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) );
if( bIsLocal[ 0 ] == bIsLocal[ 1 ] )
{
xMacEntry = x;
}
#else /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
xMacEntry = x;
#endif /* if ( ipconfigARP_STORES_REMOTE_ADDRESSES != 0 ) */
}
/* _HT_
* Shouldn't we test for xARPCache[ x ].ucValid == pdFALSE here ? */
else if( xARPCache[ x ].ucAge < ucMinAgeFound )
{
/* As the table is traversed, remember the table row that
* contains the oldest entry (the lowest age count, as ages are
* decremented to zero) so the row can be re-used if this function
* needs to add an entry that does not already exist. */
ucMinAgeFound = xARPCache[ x ].ucAge;
xUseEntry = x;
}
else
{
/* Nothing happens to this cache entry for now. */
}
}
if( xMacEntry >= 0 )
{
xUseEntry = xMacEntry;
if( xIpEntry >= 0 )
{
/* Both the MAC address as well as the IP address were found in
* different locations: clear the entry which matches the
* IP-address */
( void ) memset( &( xARPCache[ xIpEntry ] ), 0, sizeof( ARPCacheRow_t ) );
}
}
else if( xIpEntry >= 0 )
{
/* An entry containing the IP-address was found, but it had a different MAC address */
xUseEntry = xIpEntry;
}
else
{
/* No matching entry found. */
}
/* If the entry was not found, we use the oldest entry and set the IPaddress */
xARPCache[ xUseEntry ].ulIPAddress = ulIPAddress;
if( pxMACAddress != NULL )
{
( void ) memcpy( xARPCache[ xUseEntry ].xMACAddress.ucBytes, pxMACAddress->ucBytes, sizeof( pxMACAddress->ucBytes ) );
iptraceARP_TABLE_ENTRY_CREATED( ulIPAddress, ( *pxMACAddress ) );
/* And this entry does not need immediate attention */
xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_AGE;
xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdTRUE;
}
else if( xIpEntry < 0 )
{
xARPCache[ xUseEntry ].ucAge = ( uint8_t ) ipconfigMAX_ARP_RETRANSMISSIONS;
xARPCache[ xUseEntry ].ucValid = ( uint8_t ) pdFALSE;
}
else
{
/* Nothing will be stored. */
}
}
}
/*-----------------------------------------------------------*/
#if ( ipconfigUSE_ARP_REVERSED_LOOKUP == 1 )
/**
* @brief Retrieve an entry from the cache table
*
* @param[in] pxMACAddress: The MAC-address of the entry of interest.
* @param[out] pulIPAddress: set to the IP-address found, or unchanged when not found.
*
* @return Either eARPCacheMiss or eARPCacheHit.
*/
eARPLookupResult_t eARPGetCacheEntryByMac( MACAddress_t * const pxMACAddress,
uint32_t * pulIPAddress )
{
BaseType_t x;
eARPLookupResult_t eReturn = eARPCacheMiss;
configASSERT( pxMACAddress != NULL );
configASSERT( pulIPAddress != NULL );
/* Loop through each entry in the ARP cache. */
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
{
/* Does this row in the ARP cache table hold an entry for the MAC
* address being searched? */
if( memcmp( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) ) == 0 )
{
*pulIPAddress = xARPCache[ x ].ulIPAddress;
eReturn = eARPCacheHit;
break;
}
}
return eReturn;
}
#endif /* ipconfigUSE_ARP_REVERSED_LOOKUP */
/*-----------------------------------------------------------*/
/**
* @brief Look for ulIPAddress in the ARP cache.
*
* @param[in,out] pulIPAddress: Pointer to the IP-address to be queried to the ARP cache.
* @param[in,out] pxMACAddress: Pointer to a MACAddress_t variable where the MAC address
* will be stored, if found.
*
* @return If the IP address exists, copy the associated MAC address into pxMACAddress,
* refresh the ARP cache entry's age, and return eARPCacheHit. If the IP
* address does not exist in the ARP cache return eARPCacheMiss. If the packet
* cannot be sent for any reason (maybe DHCP is still in process, or the
* addressing needs a gateway but there isn't a gateway defined) then return
* eCantSendPacket.
*/
eARPLookupResult_t eARPGetCacheEntry( uint32_t * pulIPAddress,
MACAddress_t * const pxMACAddress )
{
eARPLookupResult_t eReturn;
uint32_t ulAddressToLookup;
ulAddressToLookup = *pulIPAddress;
#if ( ipconfigUSE_LLMNR == 1 )
if( ulAddressToLookup == ipLLMNR_IP_ADDR ) /* Is in network byte order. */
{
/* The LLMNR IP-address has a fixed virtual MAC address. */
( void ) memcpy( pxMACAddress->ucBytes, xLLMNR_MacAdress.ucBytes, sizeof( MACAddress_t ) );
eReturn = eARPCacheHit;
}
else
#endif
if( xIsIPv4Multicast( ulAddressToLookup ) != 0 )
{
/* Get the lowest 23 bits of the IP-address. */
vSetMultiCastIPv4MacAddress( ulAddressToLookup, pxMACAddress );
eReturn = eARPCacheHit;
}
else if( ( *pulIPAddress == ipBROADCAST_IP_ADDRESS ) || /* Is it the general broadcast address 255.255.255.255? */
( *pulIPAddress == xNetworkAddressing.ulBroadcastAddress ) ) /* Or a local broadcast address, eg 192.168.1.255? */
{printf("This is a broadcast so it uses the broadcast MAC address\r\n");
/* This is a broadcast so it uses the broadcast MAC address. */
( void ) memcpy( pxMACAddress->ucBytes, xBroadcastMACAddress.ucBytes, sizeof( MACAddress_t ) );
eReturn = eARPCacheHit;
}
else if( *ipLOCAL_IP_ADDRESS_POINTER == 0UL )
{
/* The IP address has not yet been assigned, so there is nothing that
* can be done. */
eReturn = eCantSendPacket;
}
else
{
eReturn = eARPCacheMiss;
if( ( *pulIPAddress & xNetworkAddressing.ulNetMask ) != ( ( *ipLOCAL_IP_ADDRESS_POINTER ) & xNetworkAddressing.ulNetMask ) )
{
/* No matching end-point is found, look for a gateway. */
#if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
eReturn = prvCacheLookup( *pulIPAddress, pxMACAddress );
if( eReturn == eARPCacheHit )
{
/* The stack is configured to store 'remote IP addresses', i.e. addresses
* belonging to a different the netmask. prvCacheLookup() returned a hit, so
* the MAC address is known. */
}
else
#endif
{
/* The IP address is off the local network, so look up the
* hardware address of the router, if any. */
if( xNetworkAddressing.ulGatewayAddress != ( uint32_t ) 0U )
{
ulAddressToLookup = xNetworkAddressing.ulGatewayAddress;
}
else
{
ulAddressToLookup = *pulIPAddress;
}
}
}
else
{
/* The IP address is on the local network, so lookup the requested
* IP address directly. */
ulAddressToLookup = *pulIPAddress;
}
#if ( ipconfigARP_STORES_REMOTE_ADDRESSES == 1 )
if( eReturn == eARPCacheMiss ) /*lint !e774: (Info -- Boolean within 'if' always evaluates to True, depending on configuration. */
#else
/* No cache look-up was done, so the result is still 'eARPCacheMiss'. */
#endif
{
if( ulAddressToLookup == 0UL )
{
/* The address is not on the local network, and there is not a
* router. */
eReturn = eCantSendPacket;
}
else
{
eReturn = prvCacheLookup( ulAddressToLookup, pxMACAddress );
if( eReturn == eARPCacheMiss )
{
/* It might be that the ARP has to go to the gateway. */
*pulIPAddress = ulAddressToLookup;
}
}
}
}
return eReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief Lookup an IP address in the ARP cache.
*
* @param[in] ulAddressToLookup: The 32-bit representation of an IP address to
* lookup.
* @param[out] pxMACAddress: A pointer to MACAddress_t variable where, if there
* is an ARP cache hit, the MAC address corresponding to
* the IP address will be stored.
*
* @return When the IP-address is found: eARPCacheHit, when not found: eARPCacheMiss,
* and when waiting for a ARP reply: eCantSendPacket.
*/
static eARPLookupResult_t prvCacheLookup( uint32_t ulAddressToLookup,
MACAddress_t * const pxMACAddress )
{
BaseType_t x;
eARPLookupResult_t eReturn = eARPCacheMiss;
/* Loop through each entry in the ARP cache. */
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
{
/* Does this row in the ARP cache table hold an entry for the IP address
* being queried? */
if( xARPCache[ x ].ulIPAddress == ulAddressToLookup )
{
/* A matching valid entry was found. */
if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
{
/* This entry is waiting an ARP reply, so is not valid. */
eReturn = eCantSendPacket;
}
else
{
/* A valid entry was found. */
( void ) memcpy( pxMACAddress->ucBytes, xARPCache[ x ].xMACAddress.ucBytes, sizeof( MACAddress_t ) );
eReturn = eARPCacheHit;
}
break;
}
}
return eReturn;
}
/*-----------------------------------------------------------*/
/**
* @brief A call to this function will update (or 'Age') the ARP cache entries.
* The function will also try to prevent a removal of entry by sending
* an ARP query. It will also check whether we are waiting on an ARP
* reply - if we are, then an ARP request will be re-sent.
* In case an ARP entry has 'Aged' to 0, it will be removed from the ARP
* cache.
*/
void vARPAgeCache( void )
{
BaseType_t x;
TickType_t xTimeNow;
/* Loop through each entry in the ARP cache. */
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
{
/* If the entry is valid (its age is greater than zero). */
if( xARPCache[ x ].ucAge > 0U )
{
/* Decrement the age value of the entry in this ARP cache table row.
* When the age reaches zero it is no longer considered valid. */
( xARPCache[ x ].ucAge )--;
/* If the entry is not yet valid, then it is waiting an ARP
* reply, and the ARP request should be retransmitted. */
if( xARPCache[ x ].ucValid == ( uint8_t ) pdFALSE )
{
FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
}
else if( xARPCache[ x ].ucAge <= ( uint8_t ) arpMAX_ARP_AGE_BEFORE_NEW_ARP_REQUEST )
{
/* This entry will get removed soon. See if the MAC address is
* still valid to prevent this happening. */
iptraceARP_TABLE_ENTRY_WILL_EXPIRE( xARPCache[ x ].ulIPAddress );
FreeRTOS_OutputARPRequest( xARPCache[ x ].ulIPAddress );
}
else
{
/* The age has just ticked down, with nothing to do. */
}
if( xARPCache[ x ].ucAge == 0U )
{
/* The entry is no longer valid. Wipe it out. */
iptraceARP_TABLE_ENTRY_EXPIRED( xARPCache[ x ].ulIPAddress );
xARPCache[ x ].ulIPAddress = 0UL;
}
}
}
xTimeNow = xTaskGetTickCount();
if( ( xLastGratuitousARPTime == ( TickType_t ) 0 ) || ( ( xTimeNow - xLastGratuitousARPTime ) > ( TickType_t ) arpGRATUITOUS_ARP_PERIOD ) )
{
FreeRTOS_OutputARPRequest( *ipLOCAL_IP_ADDRESS_POINTER );
xLastGratuitousARPTime = xTimeNow;
}
}
/*-----------------------------------------------------------*/
/**
* @brief Send a Gratuitous ARP packet to allow this node to announce the IP-MAC
* mapping to the entire network.
*/
void vARPSendGratuitous( void )
{
/* Setting xLastGratuitousARPTime to 0 will force a gratuitous ARP the next
* time vARPAgeCache() is called. */
xLastGratuitousARPTime = ( TickType_t ) 0;
/* Let the IP-task call vARPAgeCache(). */
( void ) xSendEventToIPTask( eARPTimerEvent );
}
/*-----------------------------------------------------------*/
/**
* @brief Create and send an ARP request packet.
*
* @param[in] ulIPAddress: A 32-bit representation of the IP-address whose
* physical (MAC) address is required.
*/
void FreeRTOS_OutputARPRequest( uint32_t ulIPAddress )
{
NetworkBufferDescriptor_t * pxNetworkBuffer;
/* This is called from the context of the IP event task, so a block time
* must not be used. */
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( ARPPacket_t ), ( TickType_t ) 0U );
if( pxNetworkBuffer != NULL )
{
pxNetworkBuffer->ulIPAddress = ulIPAddress;
vARPGenerateRequestPacket( pxNetworkBuffer );
#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
BaseType_t xIndex;
for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
{
pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
}
pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
}
}
#endif /* if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) */
if( xIsCallingFromIPTask() != 0 )
{
iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
/* Only the IP-task is allowed to call this function directly. */
( void ) xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
}
else
{
IPStackEvent_t xSendEvent;
/* Send a message to the IP-task to send this ARP packet. */
xSendEvent.eEventType = eNetworkTxEvent;
xSendEvent.pvData = pxNetworkBuffer;
if( xSendEventStructToIPTask( &xSendEvent, ( TickType_t ) portMAX_DELAY ) == pdFAIL )
{
/* Failed to send the message, so release the network buffer. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
}
}
}
/*--------------------------------------*/
/**
* @brief Generate an ARP request packet by copying various constant details to
* the buffer.
*
* @param[in,out] pxNetworkBuffer: Pointer to the buffer which has to be filled with
* the ARP request packet details.
*/
void vARPGenerateRequestPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
/* Part of the Ethernet and ARP headers are always constant when sending an IPv4
* ARP packet. This array defines the constant parts, allowing this part of the
* packet to be filled in using a simple memcpy() instead of individual writes. */
static const uint8_t xDefaultPartARPPacketHeader[] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* Ethernet destination address. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source address. */
0x08, 0x06, /* Ethernet frame type (ipARP_FRAME_TYPE). */
0x00, 0x01, /* usHardwareType (ipARP_HARDWARE_TYPE_ETHERNET). */
0x08, 0x00, /* usProtocolType. */
ipMAC_ADDRESS_LENGTH_BYTES, /* ucHardwareAddressLength. */
ipIP_ADDRESS_LENGTH_BYTES, /* ucProtocolAddressLength. */
0x00, 0x01, /* usOperation (ipARP_REQUEST). */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* xSenderHardwareAddress. */
0x00, 0x00, 0x00, 0x00, /* ulSenderProtocolAddress. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* xTargetHardwareAddress. */
};
ARPPacket_t * pxARPPacket;
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
const void * pvCopySource;
void * pvCopyDest;
/* Buffer allocation ensures that buffers always have space
* for an ARP packet. See buffer allocation implementations 1
* and 2 under portable/BufferManagement. */
configASSERT( pxNetworkBuffer != NULL );
configASSERT( pxNetworkBuffer->xDataLength >= sizeof( ARPPacket_t ) );
pxARPPacket = ipCAST_PTR_TO_TYPE_PTR( ARPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
/* memcpy the const part of the header information into the correct
* location in the packet. This copies:
* xEthernetHeader.ulDestinationAddress
* xEthernetHeader.usFrameType;
* xARPHeader.usHardwareType;
* xARPHeader.usProtocolType;
* xARPHeader.ucHardwareAddressLength;
* xARPHeader.ucProtocolAddressLength;
* xARPHeader.usOperation;
* xARPHeader.xTargetHardwareAddress;
*/
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = xDefaultPartARPPacketHeader;
pvCopyDest = pxARPPacket;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartARPPacketHeader ) );
pvCopySource = ipLOCAL_MAC_ADDRESS;
pvCopyDest = pxARPPacket->xEthernetHeader.xSourceAddress.ucBytes;
( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
pvCopySource = ipLOCAL_MAC_ADDRESS;
pvCopyDest = pxARPPacket->xARPHeader.xSenderHardwareAddress.ucBytes;
( void ) memcpy( pvCopyDest, pvCopySource, ipMAC_ADDRESS_LENGTH_BYTES );
pvCopySource = ipLOCAL_IP_ADDRESS_POINTER;
pvCopyDest = pxARPPacket->xARPHeader.ucSenderProtocolAddress;
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( pxARPPacket->xARPHeader.ucSenderProtocolAddress ) );
pxARPPacket->xARPHeader.ulTargetProtocolAddress = pxNetworkBuffer->ulIPAddress;
pxNetworkBuffer->xDataLength = sizeof( ARPPacket_t );
iptraceCREATING_ARP_REQUEST( pxNetworkBuffer->ulIPAddress );
}
/*-----------------------------------------------------------*/
/**
* @brief A call to this function will clear the ARP cache.
*/
void FreeRTOS_ClearARP( void )
{
( void ) memset( xARPCache, 0, sizeof( xARPCache ) );
}
/*-----------------------------------------------------------*/
#if 1
/**
* @brief This function will check if the target IP-address belongs to this device.
* If so, the packet will be passed to the IP-stack, who will answer it.
* The function is to be called within the function xNetworkInterfaceOutput().
*
* @param[in] pxDescriptor: The network buffer which is to be checked for loop-back.
* @param[in] bReleaseAfterSend: pdTRUE: Driver is allowed to transfer ownership of descriptor.
* pdFALSE: Driver is not allowed to take ownership of descriptor,
* make a copy of it.
*
* @return pdTRUE/pdFALSE: There is/isn't a loopback address in the packet.
*/
BaseType_t xCheckLoopback( NetworkBufferDescriptor_t * const pxDescriptor,
BaseType_t bReleaseAfterSend )
{
BaseType_t xResult = pdFALSE;
NetworkBufferDescriptor_t * pxUseDescriptor = pxDescriptor;
const IPPacket_t * pxIPPacket = ipCAST_PTR_TO_TYPE_PTR( IPPacket_t, pxUseDescriptor->pucEthernetBuffer );
if( pxIPPacket->xEthernetHeader.usFrameType == ipIPv4_FRAME_TYPE )
{
if( memcmp( pxIPPacket->xEthernetHeader.xDestinationAddress.ucBytes, ipLOCAL_MAC_ADDRESS, ipMAC_ADDRESS_LENGTH_BYTES ) == 0 )
{
xResult = pdTRUE;
if( bReleaseAfterSend == pdFALSE )
{
/* Driver is not allowed to transfer the ownership
* of descriptor, so make a copy of it */
pxUseDescriptor =
pxDuplicateNetworkBufferWithDescriptor( pxDescriptor, pxDescriptor->xDataLength );
}
if( pxUseDescriptor != NULL )
{
IPStackEvent_t xRxEvent;
xRxEvent.eEventType = eNetworkRxEvent;
xRxEvent.pvData = pxUseDescriptor;
if( xSendEventStructToIPTask( &xRxEvent, 0U ) != pdTRUE )
{
vReleaseNetworkBufferAndDescriptor( pxUseDescriptor );
iptraceETHERNET_RX_EVENT_LOST();
FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
}
}
}
}
return xResult;
}
#endif /* 0 */
/*-----------------------------------------------------------*/
#if ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 )
void FreeRTOS_PrintARPCache( void )
{
BaseType_t x, xCount = 0;
/* Loop through each entry in the ARP cache. */
for( x = 0; x < ipconfigARP_CACHE_ENTRIES; x++ )
{
if( ( xARPCache[ x ].ulIPAddress != 0UL ) && ( xARPCache[ x ].ucAge > ( uint8_t ) 0U ) )
{
/* See if the MAC-address also matches, and we're all happy */
FreeRTOS_printf( ( "Arp %2ld: %3u - %16lxip : %02x:%02x:%02x : %02x:%02x:%02x\n",
x,
xARPCache[ x ].ucAge,
xARPCache[ x ].ulIPAddress,
xARPCache[ x ].xMACAddress.ucBytes[ 0 ],
xARPCache[ x ].xMACAddress.ucBytes[ 1 ],
xARPCache[ x ].xMACAddress.ucBytes[ 2 ],
xARPCache[ x ].xMACAddress.ucBytes[ 3 ],
xARPCache[ x ].xMACAddress.ucBytes[ 4 ],
xARPCache[ x ].xMACAddress.ucBytes[ 5 ] ) );
xCount++;
}
}
FreeRTOS_printf( ( "Arp has %ld entries\n", xCount ) );
}
#endif /* ( ipconfigHAS_PRINTF != 0 ) || ( ipconfigHAS_DEBUG_PRINTF != 0 ) */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,666 @@
/*
* porting from lwip
*/
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <FreeRTOS.h>
#include <task.h>
#include "FreeRTOS_IP.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_DHCP_Server.h"
#include "NetworkBufferManagement.h"
#if (DHCP_DEBUG == LWIP_DBG_ON)
#define debug(s, ...) printf("%s: " s "\n", "DHCP", ## __VA_ARGS__)
#else
#define debug(s, ...)
#endif
/* Grow the size of the lwip dhcp_msg struct's options field, as LWIP
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
#define NETIF_MAX_HWADDR_LEN 6U
#define DHCP_FILE_LEN 128U
#define DHCP_SNAME_LEN 64U
#define DHCP_CHADDR_LEN 16U
#define LWIP_IANA_HWTYPE_ETHERNET 1
/* DHCP op codes */
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
/* DHCP message types */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
#define DHCP_MAGIC_COOKIE 0x63825363UL
/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
/* BootP options */
#define DHCP_OPTION_PAD 0
#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */
#define DHCP_OPTION_ROUTER 3
#define DHCP_OPTION_DNS_SERVER 6
#define DHCP_OPTION_HOSTNAME 12
#define DHCP_OPTION_IP_TTL 23
#define DHCP_OPTION_MTU 26
#define DHCP_OPTION_BROADCAST 28
#define DHCP_OPTION_TCP_TTL 37
#define DHCP_OPTION_NTP 42
#define DHCP_OPTION_END 255
/* DHCP options */
#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */
#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */
#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */
#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */
#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2
#define DHCP_OPTION_T1 58 /* T1 renewal time */
#define DHCP_OPTION_T2 59 /* T2 rebinding time */
#define DHCP_OPTION_US 60
#define DHCP_OPTION_CLIENT_ID 61
#define DHCP_OPTION_TFTP_SERVERNAME 66
#define DHCP_OPTION_BOOTFILE 67
/* possible combinations of overloading the file and sname fields with options */
#define DHCP_OVERLOAD_NONE 0
#define DHCP_OVERLOAD_FILE 1
#define DHCP_OVERLOAD_SNAME 2
#define DHCP_OVERLOAD_SNAME_FILE 3
#define IPADDR_ANY ((uint32_t)0x00000000UL)
#define ip4_addr_get_byte(ipaddr, idx) (((const uint8_t*)(&(ipaddr)->addr))[idx])
#define ip4_addr1(ipaddr) ip4_addr_get_byte(ipaddr, 0)
#define ip4_addr2(ipaddr) ip4_addr_get_byte(ipaddr, 1)
#define ip4_addr3(ipaddr) ip4_addr_get_byte(ipaddr, 2)
#define ip4_addr4(ipaddr) ip4_addr_get_byte(ipaddr, 3)
#define ip4_addr_copy(dest, src) ((dest).addr = (src).addr)
#define ip4_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
#define ip4_addr_isany_val(addr1) ((addr1).addr == IPADDR_ANY)
#define ip4_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_cmp(addr1, addr2) ip4_addr_cmp(addr1, addr2)
#define swap16(A) ((((uint16_t)(A) & 0xff00) >> 8) | (((uint16_t)(A) & 0x00ff) << 8))
#define swap32(A) ((((uint32_t)(A) & 0xff000000) >> 24) | \
(((uint32_t)(A) & 0x00ff0000) >> 8) | \
(((uint32_t)(A) & 0x0000ff00) << 8) | \
(((uint32_t)(A) & 0x000000ff) << 24))
#define IPADDR_BROADCAST ((uint32_t)0xffffffffUL)
static union {
char c[4];
unsigned long l;
} endian_test = {{ 'l', '?', '?', 'b' } };
#define ENDIANNESS ((char)endian_test.l)
uint16_t htons(uint16_t hs)
{
return (ENDIANNESS=='l') ? swap16(hs): hs;
}
uint32_t htonl(uint32_t hl)
{
return (ENDIANNESS=='l') ? swap32(hl): hl;
}
uint16_t ntohs(uint16_t ns)
{
return (ENDIANNESS=='l') ? swap16(ns): ns;
}
uint32_t ntohl(uint32_t nl)
{
return (ENDIANNESS=='l') ? swap32(nl): nl;
}
#include "pack_struct_start.h"
struct ip4_addr {
uint32_t addr;
};
#include "pack_struct_end.h"
typedef struct ip4_addr ip4_addr_t;
typedef ip4_addr_t ip_addr_t;
#include "pack_struct_start.h"
struct dhcp_msg
{
uint8_t op;
uint8_t htype;
uint8_t hlen;
uint8_t hops;
uint32_t xid;
uint16_t secs;
uint16_t flags;
ip4_addr_t ciaddr;
ip4_addr_t yiaddr;
ip4_addr_t siaddr;
ip4_addr_t giaddr;
uint8_t chaddr[DHCP_CHADDR_LEN];
uint8_t sname[DHCP_SNAME_LEN];
uint8_t file[DHCP_FILE_LEN];
uint32_t cookie;
uint8_t options[DHCP_OPTIONS_LEN];
};
#include "pack_struct_end.h"
typedef struct {
uint8_t hwaddr[NETIF_MAX_HWADDR_LEN];
uint8_t active;
uint32_t expires;
} dhcp_lease_t;
typedef struct {
//struct netconn *nc;
Socket_t server_handle;
uint8_t max_leases;
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;
struct dhcp_client_ctx
{
int32_t tid;
ListItem_t item;
TimerHandle_t timer;
server_state_t* state;
struct dhcp_msg msg;
};
static TaskHandle_t dhcpserver_task_handle = NULL;
static server_state_t *gState;
static List_t gdhcp_client_list;
static uint32_t gDefaultIp = 0;
uint32_t FreeRTOS_GetIPAddressSafe( void )
{
uint32_t ip = FreeRTOS_GetIPAddress();
if (0 == ip) {
return gDefaultIp;
}
return ip;
}
/* Handlers for various kinds of incoming DHCP messages */
static void handle_dhcp_discover(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *received);
static void handle_dhcp_request(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *dhcpmsg);
static void handle_dhcp_release(server_state_t* state, struct dhcp_msg *dhcpmsg);
static void send_dhcp_nak(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *dhcpmsg);
static void dhcpserver_task(void *pxParameter);
/* Utility functions */
static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length);
static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value);
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len);
static dhcp_lease_t *find_lease_slot(server_state_t* state, uint8_t *hwaddr);
/* Copy IP address as dotted decimal to 'dest', must be at least 16 bytes long */
inline static void sprintf_ipaddr(const ip4_addr_t *addr, char *dest)
{
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));
}
inline static void sprintf_ipaddr1(uint32_t addr, uint8_t *dest)
{
ip4_addr_t tmp = {0};
tmp.addr = addr;
sprintf_ipaddr(&tmp, (char*)dest);
}
void dhcpserver_start(const uint8_t ucIPAddress[4], uint32_t first_client_addr, uint8_t max_leases)
{
/* Stop any existing running dhcpserver */
if (dhcpserver_task_handle) {
return;
}
gDefaultIp = (ucIPAddress[0]) | (ucIPAddress[1] << 8) | (ucIPAddress[2] << 16) | (ucIPAddress[3] << 24);
printf("dhcpserver_start-->gDefaultIp:%x\r\n", gDefaultIp);
vListInitialise(&gdhcp_client_list);
gState = (server_state_t*)pvPortMalloc(sizeof(server_state_t));
memset(gState, 0, sizeof(*gState));
gState->max_leases = max_leases;
gState->leases = (dhcp_lease_t *)pvPortMalloc(max_leases * sizeof(dhcp_lease_t));
memset((void*)gState->leases, 0, max_leases * sizeof(dhcp_lease_t));
// state->server_if is assigned once the task is running - see comment in dhcpserver_task()
//ip4_addr_copy(gState->first_client_addr, *first_client_addr);
gState->first_client_addr.addr = first_client_addr;
/* Clear options */
ip4_addr_set_zero(&gState->router);
ip4_addr_set_zero(&gState->dns);
xTaskCreate(dhcpserver_task, "DHCP Server", configMINIMAL_STACK_SIZE * 4, (void*)gState, 5, &dhcpserver_task_handle);
}
void dhcpserver_stop(void)
{
if (dhcpserver_task_handle) {
vTaskDelete(dhcpserver_task_handle);
dhcpserver_task_handle = NULL;
vPortFree((void*)gState->leases);
vPortFree((void*)gState);
gState = NULL;
}
}
void dhcpserver_set_router(uint32_t router)
{
//ip4_addr_copy(gState->router, router);
gState->router.addr = router;
}
void dhcpserver_set_dns(uint32_t dns)
{
//ip4_addr_copy(gState->dns, dns);
gState->dns.addr = dns;
}
static void dhcpserver_task(void *pxParameter)
{
SocketSet_t xFD_Set;
BaseType_t xResult;
Socket_t xSockets;
struct freertos_sockaddr xAddress;
uint32_t xClientLength = sizeof( struct freertos_sockaddr );
int32_t lBytes;
const TickType_t xRxBlockTime = 0;
uint8_t rcv_buf[4096] = {0};
server_state_t* state = (server_state_t*)pxParameter;
uint8_t ipAddrStr[32] = {0};
xFD_Set = FreeRTOS_CreateSocketSet();
xSockets = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_DGRAM, FREERTOS_IPPROTO_UDP );
xAddress.sin_port = FreeRTOS_htons( 67 );
FreeRTOS_bind(xSockets, &xAddress, sizeof( struct freertos_sockaddr ));
FreeRTOS_setsockopt(xSockets, 0, FREERTOS_SO_RCVTIMEO, &xRxBlockTime, sizeof( xRxBlockTime ));
state->server_handle = xSockets;
while(1) {
FreeRTOS_FD_CLR(xSockets, xFD_Set, eSELECT_READ);
FreeRTOS_FD_SET( xSockets, xFD_Set, eSELECT_READ );
xResult = FreeRTOS_select( xFD_Set, portMAX_DELAY );
if (xResult == 0) {
continue;
}
struct dhcp_msg received = { 0 };
/* Receive a DHCP packet */
if( !FreeRTOS_FD_ISSET ( xSockets, xFD_Set ) ) {
}
/* Read from the socket. */
lBytes = FreeRTOS_recvfrom( xSockets, (void*)rcv_buf, sizeof(rcv_buf), 0, &xAddress,
&xClientLength );
if (lBytes <= 0)
continue;
if (lBytes < (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN))
continue;
/* expire any leases that have passed */
uint32_t now = xTaskGetTickCount();
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;
}
}
}
memcpy((void*)&received, (void*)rcv_buf, lBytes);
uint8_t *message_type = find_dhcp_option(&received, DHCP_OPTION_MESSAGE_TYPE,
DHCP_OPTION_MESSAGE_TYPE_LEN, NULL);
if(!message_type) {
debug("DHCP Server Error: No message type field found");
continue;
}
#if (DHCP_DEBUG == LWIP_DBG_ON)
sprintf_ipaddr1(xAddress.sin_addr, ipAddrStr);
debug("State dump. Message type %d from %s port:%d\r\n", *message_type, ipAddrStr, xAddress.sin_port);
for(int i = 0; i < state->max_leases; i++) {
#if 0
dhcp_lease_t *lease = &state->leases[i];
debug("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]);
#endif
}
#endif
//xAddress.sin_addr = 0xffffffffUL;
//xAddress.sin_port = ( uint16_t ) 68;
switch(*message_type) {
case DHCP_DISCOVER:
printf("DHCP_DISCOVER\r\n");
handle_dhcp_discover(state, &xAddress, &received);
break;
case DHCP_REQUEST:
printf("DHCP_REQUEST\r\n");
handle_dhcp_request(state, &xAddress, &received);
break;
case DHCP_RELEASE:
printf("DHCP_RELEASE\r\n");
handle_dhcp_release(state, &received);
break;
default:
debug("DHCP Server Error: Unsupported message type %d\r\n", *message_type);
break;
}
}
}
/*static void send_dhcp_msg(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *dhcpmsg)
{
NetworkBufferDescriptor_t * pxNetworkBuffer;
uint8_t * pucUDPPayloadBuffer = NULL;
uint32_t xClientLength = sizeof( struct freertos_sockaddr );
pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( sizeof( UDPPacket_t ) + sizeof(struct dhcp_msg), 0U );
if( pxNetworkBuffer == NULL ) {
debug("DHCP Server: malloc net buf desc err.\r\n");
return;
}
pucUDPPayloadBuffer = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
memcpy(pucUDPPayloadBuffer, (void*)dhcpmsg, sizeof(struct dhcp_msg));
FreeRTOS_sendto(state->server_handle, (void*)pucUDPPayloadBuffer, sizeof(struct dhcp_msg), FREERTOS_ZERO_COPY, xaddr, xClientLength);
}*/
#define dhcpdTIMER_SCAN_FREQUENCY_MS pdMS_TO_TICKS( 300UL )
static void handle_dhcp_discover(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *dhcpmsg)
{
uint32_t xClientLength = sizeof( struct freertos_sockaddr );
int32_t ret = -1;
struct dhcp_client_ctx *client = NULL;
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET)
return;
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN)
return;
dhcp_lease_t *freelease = find_lease_slot(state, dhcpmsg->chaddr);
if(!freelease) {
debug("DHCP Server: All leases taken.\r\n");
return; /* Nothing available, so do nothing */
}
/* Reuse the DISCOVER buffer for the OFFER response */
dhcpmsg->op = DHCP_BOOTREPLY;
dhcpmsg->htype = LWIP_IANA_HWTYPE_ETHERNET;
//bzero(dhcpmsg->options, DHCP_OPTIONS_LEN);
memset((void *)dhcpmsg->options, 0, sizeof(dhcpmsg->options));
dhcpmsg->yiaddr.addr = FreeRTOS_htonl(FreeRTOS_ntohl(state->first_client_addr.addr) + (freelease - state->leases));
//dhcpmsg->yiaddr.addr = ((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);
uint32_t ser_addr = FreeRTOS_GetIPAddressSafe();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &ser_addr, 4);
uint32_t ser_netmask = FreeRTOS_GetNetmask();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &ser_netmask, 4);//
uint32_t ser_broadcast = FreeRTOS_GetIPAddressSafe();
uint8_t* tmp_ptr_addr = (uint8_t*)&ser_broadcast;
*(tmp_ptr_addr + 3) = 0xff;
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_BROADCAST, &ser_broadcast, 4);
if (1) {
uint8_t addr_str[32] = {0};
sprintf_ipaddr1(ser_addr, addr_str);
debug("server ip:%s \r\n", addr_str);
sprintf_ipaddr1(xaddr->sin_addr, addr_str);
debug("##client ip:%s port:%d\r\n", addr_str, FreeRTOS_htons(xaddr->sin_port));
memset(addr_str, 0, sizeof(addr_str));
sprintf_ipaddr1(ser_netmask, addr_str);
debug("server netmask:%s \r\n", addr_str);
printf("send len:%d\r\n", sizeof(struct dhcp_msg));
}
//if (!ip4_addr_isany_val(state->router)) {
uint8_t addr_str11[32] = {0};
state->router.addr = FreeRTOS_GetGatewayAddress();
sprintf_ipaddr1(state->router.addr, addr_str11);
debug("router ip:%s \r\n", addr_str11);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
//}
//if (!ip4_addr_isany_val(state->dns)) {
state->dns.addr = FreeRTOS_GetGatewayAddress();
sprintf_ipaddr1(state->dns.addr, addr_str11);
debug("dns ip:%s \r\n", addr_str11);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
//}
uint32_t expiry = htonl(DHCPSERVER_LEASE_TIME);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
if (0) {
int i;
uint8_t *tmpp = (uint8_t *)dhcpmsg;
for (i = 0; i < sizeof(struct dhcp_msg); i++) {
printf("%02x ", tmpp[i]);
}printf("\r\n");
}
//xaddr->sin_addr = FreeRTOS_htonl(dhcpmsg->yiaddr.addr);
xaddr->sin_addr = 0xffffffff;//
xaddr->sin_port = ( uint16_t ) FreeRTOS_htons(68);
if (0 && NULL != client) {
memcpy((void *)&client->msg, (void *)dhcpmsg, sizeof(struct dhcp_msg));
client->state = state;
xTimerStart(client->timer, 0);
}
ret = FreeRTOS_sendto(state->server_handle, (void*)dhcpmsg, sizeof(struct dhcp_msg), 0, xaddr, xClientLength);
printf("len out:%d ret:%d\r\n", sizeof(struct dhcp_msg), ret);
if (ret != sizeof(struct dhcp_msg)) {
printf("udhcpd ret:%d\r\n", ret);
}
//send_dhcp_msg(state, xaddr, dhcpmsg);
}
static void handle_dhcp_request(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *dhcpmsg)
{
uint32_t xClientLength = sizeof( struct freertos_sockaddr );
static char ipbuf[16];
if (dhcpmsg->htype != LWIP_IANA_HWTYPE_ETHERNET) {
debug("DHCP Server Error: htype err.\r\n");
return;
}
if (dhcpmsg->hlen > NETIF_MAX_HWADDR_LEN) {
debug("DHCP Server Error: hlen err.\r\n");
return;
}
ip4_addr_t requested_ip;
ip4_addr_t any_ip = {0};
any_ip.addr = IPADDR_ANY;
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 (ip4_addr_cmp(&requested_ip, &any_ip)) {
ip4_addr_copy(requested_ip, dhcpmsg->ciaddr);
} else {
debug("DHCP Server Error: No requested IP");
send_dhcp_nak(state, xaddr, dhcpmsg);
return;
}
/* Test the first 4 octets match */
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);
debug("DHCP Server Error: %s not an allowed IP\r\n", ipbuf);
send_dhcp_nak(state, xaddr, dhcpmsg);
return;
}
/* 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) {
debug("DHCP Server Error: Address out of range\r\n");
send_dhcp_nak(state, xaddr, dhcpmsg);
return;
}
dhcp_lease_t *requested_lease = state->leases + octet_offs;
if (requested_lease->active && memcmp(requested_lease->hwaddr, dhcpmsg->chaddr,dhcpmsg->hlen))
{
debug("DHCP Server Error: Lease for address already taken\r\n");
send_dhcp_nak(state, xaddr, dhcpmsg);
return;
}
memcpy(requested_lease->hwaddr, dhcpmsg->chaddr, dhcpmsg->hlen);
sprintf_ipaddr(&requested_ip, ipbuf);
debug("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]);
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;
memset((void *)dhcpmsg->options, 0, sizeof(dhcpmsg->options));
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);
uint32_t expiry = htonl(DHCPSERVER_LEASE_TIME);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_LEASE_TIME, &expiry, 4);
uint32_t ser_addr = FreeRTOS_GetIPAddressSafe();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &ser_addr, 4);
uint32_t ser_netmask = FreeRTOS_GetNetmask();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SUBNET_MASK, &ser_netmask, 4);
//if (!ip4_addr_isany_val(state->router)) {
state->router.addr = FreeRTOS_GetGatewayAddress();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_ROUTER, &state->router, 4);
//}
//if (!ip4_addr_isany_val(state->dns)) {
state->dns.addr = FreeRTOS_GetGatewayAddress();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_DNS_SERVER, &state->dns, 4);
//}
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
xaddr->sin_addr = 0xffffffff;
xaddr->sin_port = ( uint16_t ) FreeRTOS_htons(68);
FreeRTOS_sendto(state->server_handle, (void*)dhcpmsg, sizeof(struct dhcp_msg), 0, xaddr, xClientLength);
//send_dhcp_msg(state, xaddr, dhcpmsg);
}
static void handle_dhcp_release(server_state_t* state, struct dhcp_msg *dhcpmsg)
{
dhcp_lease_t *lease = find_lease_slot(state, dhcpmsg->chaddr);
if (lease) {
lease->active = 0;
lease->expires = 0;
}
}
static void send_dhcp_nak(server_state_t* state, struct freertos_sockaddr *xaddr, struct dhcp_msg *dhcpmsg)
{
uint32_t xClientLength = sizeof( struct freertos_sockaddr );
/* Reuse 'dhcpmsg' for the NAK */
dhcpmsg->op = DHCP_BOOTREPLY;
memset((void *)dhcpmsg->options, 0, sizeof(dhcpmsg->options));
uint8_t *opt = (uint8_t *)&dhcpmsg->options;
opt = add_dhcp_option_byte(opt, DHCP_OPTION_MESSAGE_TYPE, DHCP_NAK);
uint32_t ser_addr = FreeRTOS_GetIPAddressSafe();
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_SERVER_ID, &ser_addr, 4);
opt = add_dhcp_option_bytes(opt, DHCP_OPTION_END, NULL, 0);
xaddr->sin_addr = 0xffffffff;
xaddr->sin_port = ( uint16_t ) FreeRTOS_htons(68);
FreeRTOS_sendto(state->server_handle, (void*)dhcpmsg, sizeof(struct dhcp_msg), 0, xaddr, xClientLength);
//send_dhcp_msg(state, xaddr, dhcpmsg);
}
static uint8_t *find_dhcp_option(struct dhcp_msg *msg, uint8_t option_num, uint8_t min_length, uint8_t *length)
{
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;) {
uint8_t type = *p++;
uint8_t len = *p++;
if (type == DHCP_OPTION_END)
return NULL;
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)
break;
if (length)
*length = len;
return p; /* start of actual option data */
}
p += len;
}
return NULL; /* Not found */
}
static uint8_t *add_dhcp_option_byte(uint8_t *opt, uint8_t type, uint8_t value)
{
*opt++ = type;
*opt++ = 1;
*opt++ = value;
return opt;
}
static uint8_t *add_dhcp_option_bytes(uint8_t *opt, uint8_t type, void *value, uint8_t len)
{
*opt++ = type;
if (len) {
*opt++ = len;
memcpy(opt, value, len);
}
return opt+len;
}
/* Find a free DHCP lease, or a lease already assigned to 'hwaddr' */
static dhcp_lease_t *find_lease_slot(server_state_t* state, uint8_t *hwaddr)
{
dhcp_lease_t *empty_lease = NULL;
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];
}
return empty_lease;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,225 @@
/*
* FreeRTOS+TCP V2.3.2 LTS Patch 1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_Stream_Buffer.c
* @brief Provides the API for managing/creating the stream buffers in the FreeRTOS+TCP network stack.
*/
/* Standard includes. */
#include <stdint.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
/**
* @brief Adds data to a stream buffer.
*
* @param[in,out] pxBuffer: The buffer to which the bytes will be added.
* @param[in] uxOffset: If uxOffset > 0, data will be written at an offset from uxHead
* while uxHead will not be moved yet.
* @param[in] pucData: A pointer to the data to be added.
* @param[in] uxByteCount: The number of bytes to add.
*
* @return The number of bytes added to the buffer.
*/
size_t uxStreamBufferAdd( StreamBuffer_t * pxBuffer,
size_t uxOffset,
const uint8_t * pucData,
size_t uxByteCount )
{
size_t uxSpace, uxNextHead, uxFirst;
size_t uxCount = uxByteCount;
uxSpace = uxStreamBufferGetSpace( pxBuffer );
/* If uxOffset > 0, items can be placed in front of uxHead */
if( uxSpace > uxOffset )
{
uxSpace -= uxOffset;
}
else
{
uxSpace = 0U;
}
/* The number of bytes that can be written is the minimum of the number of
* bytes requested and the number available. */
uxCount = FreeRTOS_min_uint32( uxSpace, uxCount );
if( uxCount != 0U )
{
uxNextHead = pxBuffer->uxHead;
if( uxOffset != 0U )
{
/* ( uxOffset > 0 ) means: write in front if the uxHead marker */
uxNextHead += uxOffset;
if( uxNextHead >= pxBuffer->LENGTH )
{
uxNextHead -= pxBuffer->LENGTH;
}
}
if( pucData != NULL )
{
/* Calculate the number of bytes that can be added in the first
* write - which may be less than the total number of bytes that need
* to be added if the buffer will wrap back to the beginning. */
uxFirst = FreeRTOS_min_uint32( pxBuffer->LENGTH - uxNextHead, uxCount );
/* Write as many bytes as can be written in the first write. */
( void ) memcpy( &( pxBuffer->ucArray[ uxNextHead ] ), pucData, uxFirst );
/* If the number of bytes written was less than the number that
* could be written in the first write... */
if( uxCount > uxFirst )
{
/* ...then write the remaining bytes to the start of the
* buffer. */
( void ) memcpy( pxBuffer->ucArray, &( pucData[ uxFirst ] ), uxCount - uxFirst );
}
}
if( uxOffset == 0U )
{
/* ( uxOffset == 0 ) means: write at uxHead position */
uxNextHead += uxCount;
if( uxNextHead >= pxBuffer->LENGTH )
{
uxNextHead -= pxBuffer->LENGTH;
}
pxBuffer->uxHead = uxNextHead;
}
if( xStreamBufferLessThenEqual( pxBuffer, pxBuffer->uxFront, uxNextHead ) != pdFALSE )
{
/* Advance the front pointer */
pxBuffer->uxFront = uxNextHead;
}
}
return uxCount;
}
/*-----------------------------------------------------------*/
/**
* @brief Read bytes from stream buffer.
*
* @param[in] pxBuffer: The buffer from which the bytes will be read.
* @param[in] uxOffset: can be used to read data located at a certain offset from 'lTail'.
* @param[in,out] pucData: If 'pucData' equals NULL, the function is called to advance 'lTail' only.
* @param[in] uxMaxCount: The number of bytes to read.
* @param[in] xPeek: if 'xPeek' is pdTRUE, or if 'uxOffset' is non-zero, the 'lTail' pointer will
* not be advanced.
*
* @return The count of the bytes read.
*/
size_t uxStreamBufferGet( StreamBuffer_t * pxBuffer,
size_t uxOffset,
uint8_t * pucData,
size_t uxMaxCount,
BaseType_t xPeek )
{
size_t uxSize, uxCount, uxFirst, uxNextTail;
/* How much data is available? */
uxSize = uxStreamBufferGetSize( pxBuffer );
if( uxSize > uxOffset )
{
uxSize -= uxOffset;
}
else
{
uxSize = 0U;
}
/* Use the minimum of the wanted bytes and the available bytes. */
uxCount = FreeRTOS_min_uint32( uxSize, uxMaxCount );
if( uxCount > 0U )
{
uxNextTail = pxBuffer->uxTail;
if( uxOffset != 0U )
{
uxNextTail += uxOffset;
if( uxNextTail >= pxBuffer->LENGTH )
{
uxNextTail -= pxBuffer->LENGTH;
}
}
if( pucData != NULL )
{
/* Calculate the number of bytes that can be read - which may be
* less than the number wanted if the data wraps around to the start of
* the buffer. */
uxFirst = FreeRTOS_min_uint32( pxBuffer->LENGTH - uxNextTail, uxCount );
/* Obtain the number of bytes it is possible to obtain in the first
* read. */
( void ) memcpy( pucData, &( pxBuffer->ucArray[ uxNextTail ] ), uxFirst );
/* If the total number of wanted bytes is greater than the number
* that could be read in the first read... */
if( uxCount > uxFirst )
{
/*...then read the remaining bytes from the start of the buffer. */
( void ) memcpy( &( pucData[ uxFirst ] ), pxBuffer->ucArray, uxCount - uxFirst );
}
}
if( ( xPeek == pdFALSE ) && ( uxOffset == 0UL ) )
{
/* Move the tail pointer to effectively remove the data read from
* the buffer. */
uxNextTail += uxCount;
if( uxNextTail >= pxBuffer->LENGTH )
{
uxNextTail -= pxBuffer->LENGTH;
}
pxBuffer->uxTail = uxNextTail;
}
}
return uxCount;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,448 @@
/*
* FreeRTOS+TCP V2.3.2 LTS Patch 1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/**
* @file FreeRTOS_UDP_IP.c
* @brief This file has the source code for the UDP-IP functionality of the FreeRTOS+TCP
* network stack.
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
#include "FreeRTOS_IP_Private.h"
#include "FreeRTOS_UDP_IP.h"
#include "FreeRTOS_ARP.h"
#include "FreeRTOS_DHCP.h"
#include "NetworkInterface.h"
#include "NetworkBufferManagement.h"
#if ( ipconfigUSE_DNS == 1 )
#include "FreeRTOS_DNS.h"
#endif
/** @brief The expected IP version and header length coded into the IP header itself. */
#define ipIP_VERSION_AND_HEADER_LENGTH_BYTE ( ( uint8_t ) 0x45 )
/** @brief Part of the Ethernet and IP headers are always constant when sending an IPv4
* UDP packet. This array defines the constant parts, allowing this part of the
* packet to be filled in using a simple memcpy() instead of individual writes. */
/*lint -e708 (Info -- union initialization). */
UDPPacketHeader_t xDefaultPartUDPPacketHeader =
{
/* .ucBytes : */
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* Ethernet source MAC address. */
0x08, 0x00, /* Ethernet frame type. */
ipIP_VERSION_AND_HEADER_LENGTH_BYTE, /* ucVersionHeaderLength. */
0x00, /* ucDifferentiatedServicesCode. */
0x00, 0x00, /* usLength. */
0x00, 0x00, /* usIdentification. */
0x00, 0x00, /* usFragmentOffset. */
ipconfigUDP_TIME_TO_LIVE, /* ucTimeToLive */
ipPROTOCOL_UDP, /* ucProtocol. */
0x00, 0x00, /* usHeaderChecksum. */
0x00, 0x00, 0x00, 0x00 /* Source IP address. */
}
};
/*-----------------------------------------------------------*/
/**
* @brief Process the generated UDP packet and do other checks before sending the
* packet such as ARP cache check and address resolution.
*
* @param[in] pxNetworkBuffer: The network buffer carrying the packet.
*/
void vProcessGeneratedUDPPacket( NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
UDPPacket_t * pxUDPPacket;
IPHeader_t * pxIPHeader;
eARPLookupResult_t eReturned;
uint32_t ulIPAddress = pxNetworkBuffer->ulIPAddress;
size_t uxPayloadSize;
/* memcpy() helper variables for MISRA Rule 21.15 compliance*/
const void * pvCopySource;
void * pvCopyDest;
/* Map the UDP packet onto the start of the frame. */
pxUDPPacket = ipCAST_PTR_TO_TYPE_PTR( UDPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
#if ipconfigSUPPORT_OUTGOING_PINGS == 1
if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
{
uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( ICMPPacket_t );
}
else
#endif
{
uxPayloadSize = pxNetworkBuffer->xDataLength - sizeof( UDPPacket_t );
}
/* Determine the ARP cache status for the requested IP address. */
eReturned = eARPGetCacheEntry( &( ulIPAddress ), &( pxUDPPacket->xEthernetHeader.xDestinationAddress ) );
if( eReturned != eCantSendPacket )
{
if( eReturned == eARPCacheHit )
{
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
uint8_t ucSocketOptions;
#endif
iptraceSENDING_UDP_PACKET( pxNetworkBuffer->ulIPAddress );
/* Create short cuts to the data within the packet. */
pxIPHeader = &( pxUDPPacket->xIPHeader );
#if ( ipconfigSUPPORT_OUTGOING_PINGS == 1 )
/* Is it possible that the packet is not actually a UDP packet
* after all, but an ICMP packet. */
if( pxNetworkBuffer->usPort != ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
{
UDPHeader_t * pxUDPHeader;
pxUDPHeader = &( pxUDPPacket->xUDPHeader );
pxUDPHeader->usDestinationPort = pxNetworkBuffer->usPort;
pxUDPHeader->usSourcePort = pxNetworkBuffer->usBoundPort;
pxUDPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( UDPHeader_t ) );
pxUDPHeader->usLength = FreeRTOS_htons( pxUDPHeader->usLength );
pxUDPHeader->usChecksum = 0U;
}
/* memcpy() the constant parts of the header information into
* the correct location within the packet. This fills in:
* xEthernetHeader.xSourceAddress
* xEthernetHeader.usFrameType
* xIPHeader.ucVersionHeaderLength
* xIPHeader.ucDifferentiatedServicesCode
* xIPHeader.usLength
* xIPHeader.usIdentification
* xIPHeader.usFragmentOffset
* xIPHeader.ucTimeToLive
* xIPHeader.ucProtocol
* and
* xIPHeader.usHeaderChecksum
*/
/* Save options now, as they will be overwritten by memcpy */
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
ucSocketOptions = pxNetworkBuffer->pucEthernetBuffer[ ipSOCKET_OPTIONS_OFFSET ];
}
#endif
/*
* Offset the memcpy by the size of a MAC address to start at the packet's
* Ethernet header 'source' MAC address; the preceding 'destination' should not be altered.
*/
/*
* Use helper variables for memcpy() to remain
* compliant with MISRA Rule 21.15. These should be
* optimized away.
*/
pvCopySource = xDefaultPartUDPPacketHeader.ucBytes;
/* The Ethernet source address is at offset 6. */
pvCopyDest = &pxNetworkBuffer->pucEthernetBuffer[ sizeof( MACAddress_t ) ];
( void ) memcpy( pvCopyDest, pvCopySource, sizeof( xDefaultPartUDPPacketHeader ) );
#if ipconfigSUPPORT_OUTGOING_PINGS == 1
if( pxNetworkBuffer->usPort == ( uint16_t ) ipPACKET_CONTAINS_ICMP_DATA )
{
pxIPHeader->ucProtocol = ipPROTOCOL_ICMP;
pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( ICMPHeader_t ) );
}
else
#endif /* ipconfigSUPPORT_OUTGOING_PINGS */
{
pxIPHeader->usLength = ( uint16_t ) ( uxPayloadSize + sizeof( IPHeader_t ) + sizeof( UDPHeader_t ) );
}
pxIPHeader->usLength = FreeRTOS_htons( pxIPHeader->usLength );
pxIPHeader->ulDestinationIPAddress = pxNetworkBuffer->ulIPAddress;
#if ( ipconfigUSE_LLMNR == 1 )
{
/* LLMNR messages are typically used on a LAN and they're
* not supposed to cross routers */
if( pxNetworkBuffer->ulIPAddress == ipLLMNR_IP_ADDR )
{
pxIPHeader->ucTimeToLive = 0x01;
}
}
#endif
#if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 )
{
pxIPHeader->usHeaderChecksum = 0U;
pxIPHeader->usHeaderChecksum = usGenerateChecksum( 0U, ( uint8_t * ) &( pxIPHeader->ucVersionHeaderLength ), ipSIZE_OF_IPv4_HEADER );
pxIPHeader->usHeaderChecksum = ~FreeRTOS_htons( pxIPHeader->usHeaderChecksum );
if( ( ucSocketOptions & ( uint8_t ) FREERTOS_SO_UDPCKSUM_OUT ) != 0U )
{
( void ) usGenerateProtocolChecksum( ( uint8_t * ) pxUDPPacket, pxNetworkBuffer->xDataLength, pdTRUE );
}
else
{
pxUDPPacket->xUDPHeader.usChecksum = 0U;
}
}
#endif /* if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM == 0 ) */
}
else if( eReturned == eARPCacheMiss )
{
/* Add an entry to the ARP table with a null hardware address.
* This allows the ARP timer to know that an ARP reply is
* outstanding, and perform retransmissions if necessary. */
vARPRefreshCacheEntry( NULL, ulIPAddress );
/* Generate an ARP for the required IP address. */
iptracePACKET_DROPPED_TO_GENERATE_ARP( pxNetworkBuffer->ulIPAddress );
pxNetworkBuffer->ulIPAddress = ulIPAddress;
vARPGenerateRequestPacket( pxNetworkBuffer );
}
else
{
/* The lookup indicated that an ARP request has already been
* sent out for the queried IP address. */
eReturned = eCantSendPacket;
}
}
if( eReturned != eCantSendPacket )
{
/* The network driver is responsible for freeing the network buffer
* after the packet has been sent. */
#if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
if( pxNetworkBuffer->xDataLength < ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES )
{
BaseType_t xIndex;
for( xIndex = ( BaseType_t ) pxNetworkBuffer->xDataLength; xIndex < ( BaseType_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES; xIndex++ )
{
pxNetworkBuffer->pucEthernetBuffer[ xIndex ] = 0U;
}
pxNetworkBuffer->xDataLength = ( size_t ) ipconfigETHERNET_MINIMUM_PACKET_BYTES;
}
}
#endif /* if defined( ipconfigETHERNET_MINIMUM_PACKET_BYTES ) */
iptraceNETWORK_INTERFACE_OUTPUT( pxNetworkBuffer->xDataLength, pxNetworkBuffer->pucEthernetBuffer );
( void ) xNetworkInterfaceOutput( pxNetworkBuffer, pdTRUE );
}
else
{
/* The packet can't be sent (DHCP not completed?). Just drop the
* packet. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
}
}
/*-----------------------------------------------------------*/
/**
* @brief Process the received UDP packet.
*
* @param[in] pxNetworkBuffer: The network buffer carrying the UDP packet.
* @param[in] usPort: The port number on which this packet was received.
*
* @return pdPASS in case the UDP packet could be processed. Else pdFAIL is returned.
*/
BaseType_t xProcessReceivedUDPPacket( NetworkBufferDescriptor_t * pxNetworkBuffer,
uint16_t usPort )
{
BaseType_t xReturn = pdPASS;
FreeRTOS_Socket_t * pxSocket;
configASSERT( pxNetworkBuffer != NULL );
configASSERT( pxNetworkBuffer->pucEthernetBuffer != NULL );
/* Map the ethernet buffer to the UDPPacket_t struct for easy access to the fields. */
const UDPPacket_t * pxUDPPacket = ipCAST_CONST_PTR_TO_CONST_TYPE_PTR( UDPPacket_t, pxNetworkBuffer->pucEthernetBuffer );
/* Caller must check for minimum packet size. */
pxSocket = pxUDPSocketLookup( usPort );
if( pxSocket != NULL )
{
/* When refreshing the ARP cache with received UDP packets we must be
* careful; hundreds of broadcast messages may pass and if we're not
* handling them, no use to fill the ARP cache with those IP addresses. */
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
#if ( ipconfigUSE_CALLBACKS == 1 )
{
/* Did the owner of this socket register a reception handler ? */
if( ipconfigIS_VALID_PROG_ADDRESS( pxSocket->u.xUDP.pxHandleReceive ) )
{
struct freertos_sockaddr xSourceAddress, destinationAddress;
void * pcData = &( pxNetworkBuffer->pucEthernetBuffer[ ipUDP_PAYLOAD_OFFSET_IPv4 ] );
FOnUDPReceive_t xHandler = ( FOnUDPReceive_t ) pxSocket->u.xUDP.pxHandleReceive;
xSourceAddress.sin_port = pxNetworkBuffer->usPort;
xSourceAddress.sin_addr = pxNetworkBuffer->ulIPAddress;
destinationAddress.sin_port = usPort;
destinationAddress.sin_addr = pxUDPPacket->xIPHeader.ulDestinationIPAddress;
/* The value of 'xDataLength' was proven to be at least the size of a UDP packet in prvProcessIPPacket(). */
if( xHandler( ( Socket_t ) pxSocket,
( void * ) pcData,
( size_t ) ( pxNetworkBuffer->xDataLength - ipUDP_PAYLOAD_OFFSET_IPv4 ),
&( xSourceAddress ),
&( destinationAddress ) ) != 0 )
{
xReturn = pdFAIL; /* xHandler has consumed the data, do not add it to .xWaitingPacketsList'. */
}
}
}
#endif /* ipconfigUSE_CALLBACKS */
#if ( ipconfigUDP_MAX_RX_PACKETS > 0U )
{
if( xReturn == pdPASS )
{
if( listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ) >= pxSocket->u.xUDP.uxMaxPackets )
{
FreeRTOS_debug_printf( ( "xProcessReceivedUDPPacket: buffer full %ld >= %ld port %u\n",
listCURRENT_LIST_LENGTH( &( pxSocket->u.xUDP.xWaitingPacketsList ) ),
pxSocket->u.xUDP.uxMaxPackets, pxSocket->usLocalPort ) );
xReturn = pdFAIL; /* we did not consume or release the buffer */
}
}
}
#endif /* if ( ipconfigUDP_MAX_RX_PACKETS > 0U ) */
#if ( ipconfigUSE_CALLBACKS == 1 ) || ( ipconfigUDP_MAX_RX_PACKETS > 0U )
if( xReturn == pdPASS ) /*lint !e774: Boolean within 'if' always evaluates to True, depending on configuration. [MISRA 2012 Rule 14.3, required. */
#else
/* xReturn is still pdPASS. */
#endif
{
vTaskSuspendAll();
{
taskENTER_CRITICAL();
{
/* Add the network packet to the list of packets to be
* processed by the socket. */
vListInsertEnd( &( pxSocket->u.xUDP.xWaitingPacketsList ), &( pxNetworkBuffer->xBufferListItem ) );
}
taskEXIT_CRITICAL();
}
( void ) xTaskResumeAll();
/* Set the socket's receive event */
if( pxSocket->xEventGroup != NULL )
{
( void ) xEventGroupSetBits( pxSocket->xEventGroup, ( EventBits_t ) eSOCKET_RECEIVE );
}
#if ( ipconfigSUPPORT_SELECT_FUNCTION == 1 )
{
if( ( pxSocket->pxSocketSet != NULL ) && ( ( pxSocket->xSelectBits & ( ( EventBits_t ) eSELECT_READ ) ) != 0U ) )
{
( void ) xEventGroupSetBits( pxSocket->pxSocketSet->xSelectGroup, ( EventBits_t ) eSELECT_READ );
}
}
#endif
#if ( ipconfigSOCKET_HAS_USER_SEMAPHORE == 1 )
{
if( pxSocket->pxUserSemaphore != NULL )
{
( void ) xSemaphoreGive( pxSocket->pxUserSemaphore );
}
}
#endif
#if ( ipconfigUSE_DHCP == 1 )
{
if( xIsDHCPSocket( pxSocket ) != 0 )
{
( void ) xSendDHCPEvent();
}
}
#endif
}
}
else
{
/* There is no socket listening to the target port, but still it might
* be for this node. */
#if ( ipconfigUSE_DNS == 1 ) && ( ipconfigDNS_USE_CALLBACKS == 1 )
/* A DNS reply, check for the source port. Although the DNS client
* does open a UDP socket to send a messages, this socket will be
* closed after a short timeout. Messages that come late (after the
* socket is closed) will be treated here. */
if( FreeRTOS_ntohs( pxUDPPacket->xUDPHeader.usSourcePort ) == ( uint16_t ) ipDNS_PORT )
{
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
}
else
#endif
#if ( ipconfigUSE_LLMNR == 1 )
/* A LLMNR request, check for the destination port. */
if( ( usPort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) ||
( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipLLMNR_PORT ) ) )
{
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
xReturn = ( BaseType_t ) ulDNSHandlePacket( pxNetworkBuffer );
}
else
#endif /* ipconfigUSE_LLMNR */
#if ( ipconfigUSE_NBNS == 1 )
/* a NetBIOS request, check for the destination port */
if( ( usPort == FreeRTOS_ntohs( ipNBNS_PORT ) ) ||
( pxUDPPacket->xUDPHeader.usSourcePort == FreeRTOS_ntohs( ipNBNS_PORT ) ) )
{
vARPRefreshCacheEntry( &( pxUDPPacket->xEthernetHeader.xSourceAddress ), pxUDPPacket->xIPHeader.ulSourceIPAddress );
xReturn = ( BaseType_t ) ulNBNSHandlePacket( pxNetworkBuffer );
}
else
#endif /* ipconfigUSE_NBNS */
{
xReturn = pdFAIL;
}
}
return xReturn;
}
/*-----------------------------------------------------------*/

View File

@ -0,0 +1,371 @@
/*
* FreeRTOS V202112.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* A set of tasks are created that send TCP echo requests to the standard echo
* port (port 7) on the IP address set by the configECHO_SERVER_ADDR0 to
* configECHO_SERVER_ADDR3 constants, then wait for and verify the reply
* (another demo is available that demonstrates the reception being performed in
* a task other than that from with the request was made).
*
* See the following web page for essential demo usage and configuration
* details:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/examples_FreeRTOS_simulator.html
*/
/* Standard includes. */
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
/* FreeRTOS includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* FreeRTOS+TCP includes. */
#include "FreeRTOS_IP.h"
#include "FreeRTOS_Sockets.h"
/* Exclude the whole file if FreeRTOSIPConfig.h is configured to use UDP only. */
#if ( ipconfigUSE_TCP == 1 )
/* The echo tasks create a socket, send out a number of echo requests, listen
for the echo reply, then close the socket again before starting over. This
delay is used between each iteration to ensure the network does not get too
congested. */
#define echoLOOP_DELAY ( ( TickType_t ) 150 / portTICK_PERIOD_MS )
/* The echo server is assumed to be on port 7, which is the standard echo
protocol port. */
#define echoECHO_PORT ( 7 )
/* The size of the buffers is a multiple of the MSS - the length of the data
sent is a pseudo random size between 20 and echoBUFFER_SIZES. */
#define echoBUFFER_SIZE_MULTIPLIER ( 3 )
#define echoBUFFER_SIZES ( ipconfigTCP_MSS * echoBUFFER_SIZE_MULTIPLIER )
/* The number of instances of the echo client task to create. */
#define echoNUM_ECHO_CLIENTS ( 1 )
/*-----------------------------------------------------------*/
/*
* Uses a socket to send data to, then receive data from, the standard echo
* port number 7.
*/
static void prvEchoClientTask( void *pvParameters );
/*
* Creates a pseudo random sized buffer of data to send to the echo server.
*/
static BaseType_t prvCreateTxData( char *ucBuffer,
uint32_t ulBufferLength );
/*-----------------------------------------------------------*/
/* Rx and Tx time outs are used to ensure the sockets do not wait too long for
missing data. */
static const TickType_t xReceiveTimeOut = pdMS_TO_TICKS( 4000 );
static const TickType_t xSendTimeOut = pdMS_TO_TICKS( 2000 );
/* Counters for each created task - for inspection only. */
static uint32_t ulTxRxCycles[ echoNUM_ECHO_CLIENTS ] = { 0 },
ulTxRxFailures[ echoNUM_ECHO_CLIENTS ] = { 0 },
ulConnections[ echoNUM_ECHO_CLIENTS ] = { 0 };
/* Rx and Tx buffers for each created task. */
static char cTxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ],
cRxBuffers[ echoNUM_ECHO_CLIENTS ][ echoBUFFER_SIZES ];
/*-----------------------------------------------------------*/
void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize,
UBaseType_t uxTaskPriority )
{
BaseType_t x;
/* Create the echo client tasks. */
for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ )
{
xTaskCreate( prvEchoClientTask, /* The function that implements the task. */
"Echo0", /* Just a text name for the task to aid debugging. */
usTaskStackSize, /* The stack size is defined in FreeRTOSIPConfig.h. */
( void * ) x, /* The task parameter, not used in this case. */
uxTaskPriority, /* The priority assigned to the task is defined in FreeRTOSConfig.h. */
NULL ); /* The task handle is not used. */
}
}
/*-----------------------------------------------------------*/
static void prvEchoClientTask( void *pvParameters )
{
Socket_t xSocket;
struct freertos_sockaddr xEchoServerAddress;
int32_t lLoopCount = 0UL;
const int32_t lMaxLoopCount = 1;
volatile uint32_t ulTxCount = 0UL;
BaseType_t xReceivedBytes, xReturned, xInstance;
BaseType_t lTransmitted, lStringLength;
char *pcTransmittedString, *pcReceivedString;
WinProperties_t xWinProps;
TickType_t xTimeOnEntering;
BaseType_t ret;
/* Fill in the buffer and window sizes that will be used by the socket. */
xWinProps.lTxBufSize = 6 * ipconfigTCP_MSS;
xWinProps.lTxWinSize = 3;
xWinProps.lRxBufSize = 6 * ipconfigTCP_MSS;
xWinProps.lRxWinSize = 3;
/* This task can be created a number of times. Each instance is numbered
to enable each instance to use a different Rx and Tx buffer. The number is
passed in as the task's parameter. */
xInstance = ( BaseType_t ) pvParameters;
/* Point to the buffers to be used by this instance of this task. */
pcTransmittedString = &( cTxBuffers[ xInstance ][ 0 ] );
pcReceivedString = &( cRxBuffers[ xInstance ][ 0 ] );
/* Echo requests are sent to the echo server. The address of the echo
server is configured by the constants configECHO_SERVER_ADDR0 to
configECHO_SERVER_ADDR3 in FreeRTOSConfig.h. */
xEchoServerAddress.sin_port = FreeRTOS_htons( echoECHO_PORT );
xEchoServerAddress.sin_addr = FreeRTOS_inet_addr_quick( configECHO_SERVER_ADDR0,
configECHO_SERVER_ADDR1,
configECHO_SERVER_ADDR2,
configECHO_SERVER_ADDR3 );
for( ; ; )
{
/* Create a TCP socket. */
xSocket = FreeRTOS_socket( FREERTOS_AF_INET, FREERTOS_SOCK_STREAM, FREERTOS_IPPROTO_TCP );
configASSERT( xSocket != FREERTOS_INVALID_SOCKET );
/* Set a time out so a missing reply does not cause the task to block
indefinitely. */
FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_RCVTIMEO, &xReceiveTimeOut, sizeof( xReceiveTimeOut ) );
FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_SNDTIMEO, &xSendTimeOut, sizeof( xSendTimeOut ) );
/* Set the window and buffer sizes. */
FreeRTOS_setsockopt( xSocket, 0, FREERTOS_SO_WIN_PROPERTIES, ( void * ) &xWinProps, sizeof( xWinProps ) );
/* Connect to the echo server. */
printf( "connecting to echo server....\n" );
ret = FreeRTOS_connect( xSocket, &xEchoServerAddress, sizeof( xEchoServerAddress ) );
if( ret == 0 )
{
printf( "Connected to server.. \n" );
ulConnections[ xInstance ]++;
/* Send a number of echo requests. */
for( lLoopCount = 0; lLoopCount < lMaxLoopCount; lLoopCount++ )
{
/* Create the string that is sent to the echo server. */
lStringLength = prvCreateTxData( pcTransmittedString, echoBUFFER_SIZES );
/* Add in some unique text at the front of the string. */
sprintf( pcTransmittedString, "TxRx message number %u", ulTxCount );
ulTxCount++;
printf( "sending data to the echo server \n" );
/* Send the string to the socket. */
lTransmitted = FreeRTOS_send( xSocket, /* The socket being sent to. */
( void * ) pcTransmittedString, /* The data being sent. */
lStringLength, /* The length of the data being sent. */
0 ); /* No flags. */
if( lTransmitted < 0 )
{
/* Error? */
break;
}
/* Clear the buffer into which the echoed string will be
placed. */
memset( ( void * ) pcReceivedString, 0x00, echoBUFFER_SIZES );
xReceivedBytes = 0;
/* Receive data echoed back to the socket. */
while( xReceivedBytes < lTransmitted )
{
xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */
&( pcReceivedString[ xReceivedBytes ] ), /* The buffer into which the received data will be written. */
lStringLength - xReceivedBytes, /* The size of the buffer provided to receive the data. */
0 ); /* No flags. */
if( xReturned < 0 )
{
/* Error occurred. Latch it so it can be detected
below. */
xReceivedBytes = xReturned;
break;
}
else if( xReturned == 0 )
{
/* Timed out. */
break;
}
else
{
/* Keep a count of the bytes received so far. */
xReceivedBytes += xReturned;
}
}
/* If an error occurred it will be latched in xReceivedBytes,
otherwise xReceived bytes will be just that - the number of
bytes received from the echo server. */
if( xReceivedBytes > 0 )
{
/* Compare the transmitted string to the received string. */
configASSERT( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 );
if( strncmp( pcReceivedString, pcTransmittedString, lTransmitted ) == 0 )
{
/* The echo reply was received without error. */
ulTxRxCycles[ xInstance ]++;
}
else
{
/* The received string did not match the transmitted
string. */
ulTxRxFailures[ xInstance ]++;
break;
}
}
else if( xReceivedBytes < 0 )
{
/* FreeRTOS_recv() returned an error. */
break;
}
else
{
/* Timed out without receiving anything? */
break;
}
}
/* Finished using the connected socket, initiate a graceful close:
FIN, FIN+ACK, ACK. */
FreeRTOS_shutdown( xSocket, FREERTOS_SHUT_RDWR );
/* Expect FreeRTOS_recv() to return an error once the shutdown is
complete. */
xTimeOnEntering = xTaskGetTickCount();
do
{
xReturned = FreeRTOS_recv( xSocket, /* The socket being received from. */
&( pcReceivedString[ 0 ] ), /* The buffer into which the received data will be written. */
echoBUFFER_SIZES, /* The size of the buffer provided to receive the data. */
0 );
if( xReturned < 0 )
{
break;
}
} while( ( xTaskGetTickCount() - xTimeOnEntering ) < xReceiveTimeOut );
}
else
{
printf( "Could not connect to server %ld\n", ret );
}
/* Close this socket before looping back to create another. */
FreeRTOS_closesocket( xSocket );
/* Pause for a short while to ensure the network is not too
congested. */
vTaskDelay( echoLOOP_DELAY );
}
}
/*-----------------------------------------------------------*/
static BaseType_t prvCreateTxData( char *cBuffer,
uint32_t ulBufferLength )
{
BaseType_t lCharactersToAdd, lCharacter;
char cChar = '0';
const BaseType_t lMinimumLength = 60;
/* Randomise the number of characters that will be sent in the echo
request. */
do
{
lCharactersToAdd = ipconfigRAND32() % ( ulBufferLength - 20UL );
} while( ( lCharactersToAdd == 0 ) || ( lCharactersToAdd < lMinimumLength ) ); /* Must be at least enough to add the unique text to the start of the string later. */
/* Fill the buffer. */
for( lCharacter = 0; lCharacter < lCharactersToAdd; lCharacter++ )
{
cBuffer[ lCharacter ] = cChar;
cChar++;
if( cChar > '~' )
{
cChar = '0';
}
}
return lCharactersToAdd;
}
/*-----------------------------------------------------------*/
BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void )
{
static uint32_t ulLastEchoSocketCount[ echoNUM_ECHO_CLIENTS ] = { 0 }, ulLastConnections[ echoNUM_ECHO_CLIENTS ] = { 0 };
BaseType_t xReturn = pdPASS, x;
/* Return fail is the number of cycles does not increment between
consecutive calls. */
for( x = 0; x < echoNUM_ECHO_CLIENTS; x++ )
{
if( ulTxRxCycles[ x ] == ulLastEchoSocketCount[ x ] )
{
xReturn = pdFAIL;
}
else
{
ulLastEchoSocketCount[ x ] = ulTxRxCycles[ x ];
}
if( ulConnections[ x ] == ulLastConnections[ x ] )
{
xReturn = pdFAIL;
}
else
{
ulConnections[ x ] = ulLastConnections[ x ];
}
}
return xReturn;
}
#endif /* ipconfigUSE_TCP */

View File

@ -0,0 +1,39 @@
/*
* FreeRTOS V202112.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
#ifndef SINGLE_TASK_TCP_ECHO_CLIENTS_H
#define SINGLE_TASK_TCP_ECHO_CLIENTS_H
/*
* Create the TCP echo client tasks. This is the version where an echo request
* is made from the same task that listens for the echo reply.
*/
void vStartTCPEchoClientTasks_SingleTasks( uint16_t usTaskStackSize, UBaseType_t uxTaskPriority );
BaseType_t xAreSingleTaskTCPEchoClientsStillRunning( void );
#endif /* SINGLE_TASK_TCP_ECHO_CLIENTS_H */

View File

@ -0,0 +1,321 @@
/*
* FreeRTOS Kernel V10.4.1
* Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://aws.amazon.com/freertos
* http://www.FreeRTOS.org
*/
/*****************************************************************************
*
* See the following URL for configuration information.
* http://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html
*
*****************************************************************************/
#ifndef FREERTOS_IP_CONFIG_H
#define FREERTOS_IP_CONFIG_H
/* Set to 1 to print out debug messages. If ipconfigHAS_DEBUG_PRINTF is set to
* 1 then FreeRTOS_debug_printf should be defined to the function used to print
* out the debugging messages. */
#define ipconfigHAS_DEBUG_PRINTF 0
#if ( ipconfigHAS_DEBUG_PRINTF == 1 )
#define FreeRTOS_debug_printf( X ) printf X
//configPRINTF( X )
#endif
/* Set to 1 to print out non debugging messages, for example the output of the
* FreeRTOS_netstat() command, and ping replies. If ipconfigHAS_PRINTF is set to 1
* then FreeRTOS_printf should be set to the function used to print out the
* messages. */
#define ipconfigHAS_PRINTF 1
#if ( ipconfigHAS_PRINTF == 1 )
#define FreeRTOS_printf( X ) configPRINTF( X )
#endif
/* Define the byte order of the target MCU (the MCU FreeRTOS+TCP is executing
* on). Valid options are pdFREERTOS_BIG_ENDIAN and pdFREERTOS_LITTLE_ENDIAN. */
#define ipconfigBYTE_ORDER pdFREERTOS_LITTLE_ENDIAN
/* If the network card/driver includes checksum offloading (IP/TCP/UDP checksums)
* then set ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM to 1 to prevent the software
* stack repeating the checksum calculations. */
#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1
/* Several API's will block until the result is known, or the action has been
* performed, for example FreeRTOS_send() and FreeRTOS_recv(). The timeouts can be
* set per socket, using setsockopt(). If not set, the times below will be
* used as defaults. */
#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME ( 5000 )
#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME ( 5000 )
/* Include support for DNS caching. For TCP, having a small DNS cache is very
* useful. When a cache is present, ipconfigDNS_REQUEST_ATTEMPTS can be kept low
* and also DNS may use small timeouts. If a DNS reply comes in after the DNS
* socket has been destroyed, the result will be stored into the cache. The next
* call to FreeRTOS_gethostbyname() will return immediately, without even creating
* a socket.
*/
#define ipconfigUSE_DNS_CACHE ( 1 )
#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY ( 6 )
#define ipconfigDNS_REQUEST_ATTEMPTS ( 2 )
/* The IP stack executes it its own task (although any application task can make
* use of its services through the published sockets API). ipconfigUDP_TASK_PRIORITY
* sets the priority of the task that executes the IP stack. The priority is a
* standard FreeRTOS task priority so can take any value from 0 (the lowest
* priority) to (configMAX_PRIORITIES - 1) (the highest priority).
* configMAX_PRIORITIES is a standard FreeRTOS configuration parameter defined in
* FreeRTOSConfig.h, not FreeRTOSIPConfig.h. Consideration needs to be given as to
* the priority assigned to the task executing the IP stack relative to the
* priority assigned to tasks that use the IP stack. */
#define ipconfigIP_TASK_PRIORITY ( configMAX_PRIORITIES - 2 )
/* The size, in words (not bytes), of the stack allocated to the FreeRTOS+TCP
* task. This setting is less important when the FreeRTOS Win32 simulator is used
* as the Win32 simulator only stores a fixed amount of information on the task
* stack. FreeRTOS includes optional stack overflow detection, see:
* http://www.freertos.org/Stacks-and-stack-overflow-checking.html. */
#define ipconfigIP_TASK_STACK_SIZE_WORDS ( configMINIMAL_STACK_SIZE * 5 )
/* ipconfigRAND32() is called by the IP stack to generate random numbers for
* things such as a DHCP transaction number or initial sequence number. Random
* number generation is performed via this macro to allow applications to use their
* own random number generation method. For example, it might be possible to
* generate a random number by sampling noise on an analogue input. */
extern uint32_t ulRand();
#define ipconfigRAND32() ulRand()
/* If ipconfigUSE_NETWORK_EVENT_HOOK is set to 1 then FreeRTOS+TCP will call the
* network event hook at the appropriate times. If ipconfigUSE_NETWORK_EVENT_HOOK
* is not set to 1 then the network event hook will never be called. See:
* http://www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_UDP/API/vApplicationIPNetworkEventHook.shtml.
*/
#define ipconfigUSE_NETWORK_EVENT_HOOK 0
/* Sockets have a send block time attribute. If FreeRTOS_sendto() is called but
* a network buffer cannot be obtained then the calling task is held in the Blocked
* state (so other tasks can continue to executed) until either a network buffer
* becomes available or the send block time expires. If the send block time expires
* then the send operation is aborted. The maximum allowable send block time is
* capped to the value set by ipconfigMAX_SEND_BLOCK_TIME_TICKS. Capping the
* maximum allowable send block time prevents prevents a deadlock occurring when
* all the network buffers are in use and the tasks that process (and subsequently
* free) the network buffers are themselves blocked waiting for a network buffer.
* ipconfigMAX_SEND_BLOCK_TIME_TICKS is specified in RTOS ticks. A time in
* milliseconds can be converted to a time in ticks by dividing the time in
* milliseconds by portTICK_PERIOD_MS. */
#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( 5000U / portTICK_PERIOD_MS )
/* If ipconfigUSE_DHCP is 1 then FreeRTOS+TCP will attempt to retrieve an IP
* address, netmask, DNS server address and gateway address from a DHCP server. If
* ipconfigUSE_DHCP is 0 then FreeRTOS+TCP will use a static IP address. The
* stack will revert to using the static IP address even when ipconfigUSE_DHCP is
* set to 1 if a valid configuration cannot be obtained from a DHCP server for any
* reason. The static configuration used is that passed into the stack by the
* FreeRTOS_IPInit() function call. */
#define ipconfigUSE_DHCP 1
#define ipconfigDHCP_REGISTER_HOSTNAME 0
#define ipconfigDHCP_USES_UNICAST 1
/* If ipconfigDHCP_USES_USER_HOOK is set to 1 then the application writer must
* provide an implementation of the DHCP callback function,
* xApplicationDHCPUserHook(). */
#define ipconfigUSE_DHCP_HOOK 1
/* When ipconfigUSE_DHCP is set to 1, DHCP requests will be sent out at
* increasing time intervals until either a reply is received from a DHCP server
* and accepted, or the interval between transmissions reaches
* ipconfigMAXIMUM_DISCOVER_TX_PERIOD. The IP stack will revert to using the
* static IP address passed as a parameter to FreeRTOS_IPInit() if the
* re-transmission time interval reaches ipconfigMAXIMUM_DISCOVER_TX_PERIOD without
* a DHCP reply being received. */
#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD \
( 120000U / portTICK_PERIOD_MS )
/* The ARP cache is a table that maps IP addresses to MAC addresses. The IP
* stack can only send a UDP message to a remove IP address if it knowns the MAC
* address associated with the IP address, or the MAC address of the router used to
* contact the remote IP address. When a UDP message is received from a remote IP
* address the MAC address and IP address are added to the ARP cache. When a UDP
* message is sent to a remote IP address that does not already appear in the ARP
* cache then the UDP message is replaced by a ARP message that solicits the
* required MAC address information. ipconfigARP_CACHE_ENTRIES defines the maximum
* number of entries that can exist in the ARP table at any one time. */
#define ipconfigARP_CACHE_ENTRIES 6
/* ARP requests that do not result in an ARP response will be re-transmitted a
* maximum of ipconfigMAX_ARP_RETRANSMISSIONS times before the ARP request is
* aborted. */
#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5 )
/* ipconfigMAX_ARP_AGE defines the maximum time between an entry in the ARP
* table being created or refreshed and the entry being removed because it is stale.
* New ARP requests are sent for ARP cache entries that are nearing their maximum
* age. ipconfigMAX_ARP_AGE is specified in tens of seconds, so a value of 150 is
* equal to 1500 seconds (or 25 minutes). */
#define ipconfigMAX_ARP_AGE 150
/* Implementing FreeRTOS_inet_addr() necessitates the use of string handling
* routines, which are relatively large. To save code space the full
* FreeRTOS_inet_addr() implementation is made optional, and a smaller and faster
* alternative called FreeRTOS_inet_addr_quick() is provided. FreeRTOS_inet_addr()
* takes an IP in decimal dot format (for example, "192.168.0.1") as its parameter.
* FreeRTOS_inet_addr_quick() takes an IP address as four separate numerical octets
* (for example, 192, 168, 0, 1) as its parameters. If
* ipconfigINCLUDE_FULL_INET_ADDR is set to 1 then both FreeRTOS_inet_addr() and
* FreeRTOS_indet_addr_quick() are available. If ipconfigINCLUDE_FULL_INET_ADDR is
* not set to 1 then only FreeRTOS_indet_addr_quick() is available. */
#define ipconfigINCLUDE_FULL_INET_ADDR 1
/* ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS defines the total number of network buffer that
* are available to the IP stack. The total number of network buffers is limited
* to ensure the total amount of RAM that can be consumed by the IP stack is capped
* to a pre-determinable value. */
#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 60
/* A FreeRTOS queue is used to send events from application tasks to the IP
* stack. ipconfigEVENT_QUEUE_LENGTH sets the maximum number of events that can
* be queued for processing at any one time. The event queue must be a minimum of
* 5 greater than the total number of network buffers. */
#define ipconfigEVENT_QUEUE_LENGTH \
( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )
/* The address of a socket is the combination of its IP address and its port
* number. FreeRTOS_bind() is used to manually allocate a port number to a socket
* (to 'bind' the socket to a port), but manual binding is not normally necessary
* for client sockets (those sockets that initiate outgoing connections rather than
* wait for incoming connections on a known port number). If
* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 1 then calling
* FreeRTOS_sendto() on a socket that has not yet been bound will result in the IP
* stack automatically binding the socket to a port number from the range
* socketAUTO_PORT_ALLOCATION_START_NUMBER to 0xffff. If
* ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND is set to 0 then calling FreeRTOS_sendto()
* on a socket that has not yet been bound will result in the send operation being
* aborted. */
#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1
/* Defines the Time To Live (TTL) values used in outgoing UDP packets. */
#define ipconfigUDP_TIME_TO_LIVE 128
/* Also defined in FreeRTOSIPConfigDefaults.h. */
#define ipconfigTCP_TIME_TO_LIVE 128
/* USE_TCP: Use TCP and all its features. */
#define ipconfigUSE_TCP ( 1 )
/* USE_WIN: Let TCP use windowing mechanism. */
#define ipconfigUSE_TCP_WIN ( 1 )
/* The MTU is the maximum number of bytes the payload of a network frame can
* contain. For normal Ethernet V2 frames the maximum MTU is 1500. Setting a
* lower value can save RAM, depending on the buffer management scheme used. If
* ipconfigCAN_FRAGMENT_OUTGOING_PACKETS is 1 then (ipconfigNETWORK_MTU - 28) must
* be divisible by 8. */
#define ipconfigNETWORK_MTU 1500U
/* Set ipconfigUSE_DNS to 1 to include a basic DNS client/resolver. DNS is used
* through the FreeRTOS_gethostbyname() API function. */
#define ipconfigUSE_DNS 0
/* If ipconfigREPLY_TO_INCOMING_PINGS is set to 1 then the IP stack will
* generate replies to incoming ICMP echo (ping) requests. */
#define ipconfigREPLY_TO_INCOMING_PINGS 1
/* If ipconfigSUPPORT_OUTGOING_PINGS is set to 1 then the
* FreeRTOS_SendPingRequest() API function is available. */
#define ipconfigSUPPORT_OUTGOING_PINGS 1
/* If ipconfigSUPPORT_SELECT_FUNCTION is set to 1 then the FreeRTOS_select()
* (and associated) API function is available. */
#define ipconfigSUPPORT_SELECT_FUNCTION 1
/* If ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES is set to 1 then Ethernet frames
* that are not in Ethernet II format will be dropped. This option is included for
* potential future IP stack developments. */
#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1
/* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1 then it is the
* responsibility of the Ethernet interface to filter out packets that are of no
* interest. If the Ethernet interface does not implement this functionality, then
* set ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES to 0 to have the IP stack
* perform the filtering instead (it is much less efficient for the stack to do it
* because the packet will already have been passed into the stack). If the
* Ethernet driver does all the necessary filtering in hardware then software
* filtering can be removed by using a value other than 1 or 0. */
#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1
/* The windows simulator cannot really simulate MAC interrupts, and needs to
* block occasionally to allow other tasks to run. */
#define configWINDOWS_MAC_INTERRUPT_SIMULATOR_DELAY ( 20 / portTICK_PERIOD_MS )
/* Advanced only: in order to access 32-bit fields in the IP packets with
* 32-bit memory instructions, all packets will be stored 32-bit-aligned,
* plus 16-bits. This has to do with the contents of the IP-packets: all
* 32-bit fields are 32-bit-aligned, plus 16-bit. */
#define ipconfigPACKET_FILLER_SIZE 2U
/* Define the size of the pool of TCP window descriptors. On the average, each
* TCP socket will use up to 2 x 6 descriptors, meaning that it can have 2 x 6
* outstanding packets (for Rx and Tx). When using up to 10 TP sockets
* simultaneously, one could define TCP_WIN_SEG_COUNT as 120. */
#define ipconfigTCP_WIN_SEG_COUNT 240
/* Each TCP socket has a circular buffers for Rx and Tx, which have a fixed
* maximum size. Define the size of Rx buffer for TCP sockets. */
#define ipconfigTCP_RX_BUFFER_LENGTH ( 10000 )
/* Define the size of Tx buffer for TCP sockets. */
#define ipconfigTCP_TX_BUFFER_LENGTH ( 10000 )
/* When using call-back handlers, the driver may check if the handler points to
* real program memory (RAM or flash) or just has a random non-zero value. */
#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL )
/* Include support for TCP keep-alive messages. */
#define ipconfigTCP_KEEP_ALIVE ( 1 )
#define ipconfigTCP_KEEP_ALIVE_INTERVAL ( 20 ) /* Seconds. */
/* The socket semaphore is used to unblock the MQTT task. */
#define ipconfigSOCKET_HAS_USER_SEMAPHORE ( 1 )
#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK ( 1 )
#define ipconfigUSE_CALLBACKS ( 0 )
#define portINLINE inline
#define USE_IPERF 1
#define ipconfigIPERF_DOES_ECHO_UDP 1
#define ipconfigIPERF_VERSION 3
#define ipconfigIPERF_STACK_SIZE_IPERF_TASK 680
#define ipconfigIPERF_TX_BUFSIZE ( 26 * ipconfigTCP_MSS )
#define ipconfigIPERF_TX_WINSIZE ( 26 )
#define ipconfigIPERF_RX_BUFSIZE ( 48 * ipconfigTCP_MSS )
#define ipconfigIPERF_RX_WINSIZE ( 48 )
/* The iperf module declares a character buffer to store its send data. */
#define ipconfigIPERF_RECV_BUFFER_SIZE ( 36 * ipconfigTCP_MSS )
#define ipconfigSUPPORT_SIGNALS 1
#endif /* FREERTOS_IP_CONFIG_H */

View File

@ -0,0 +1,629 @@
/*
* FreeRTOS+TCP V2.3.2 LTS Patch 1
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* 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.
*
* http://www.FreeRTOS.org
* http://aws.amazon.com/freertos
*
* 1 tab == 4 spaces!
*/
#ifndef FREERTOS_DEFAULT_IP_CONFIG_H
#define FREERTOS_DEFAULT_IP_CONFIG_H
/* The error numbers defined in this file will be moved to the core FreeRTOS
* code in future versions of FreeRTOS - at which time the following header file
* will be removed. */
#include "FreeRTOS_errno_TCP.h"
/* This file provides default values for configuration options that are missing
* from the FreeRTOSIPConfig.h configuration header file. */
/* These macros are used to define away static keyword for CBMC proofs */
#ifndef _static
#define _static static
#endif
/* Ensure defined configuration constants are using the most up to date naming. */
#ifdef tcpconfigIP_TIME_TO_LIVE
#error now called: ipconfigTCP_TIME_TO_LIVE
#endif
#ifdef updconfigIP_TIME_TO_LIVE
#error now called: ipconfigUDP_TIME_TO_LIVE
#endif
#ifdef ipFILLER_SIZE
#error now called: ipconfigPACKET_FILLER_SIZE
#endif
#ifdef dnsMAX_REQUEST_ATTEMPTS
#error now called: ipconfigDNS_REQUEST_ATTEMPTS
#endif
#ifdef ipconfigUDP_TASK_PRIORITY
#error now called: ipconfigIP_TASK_PRIORITY
#endif
#ifdef ipconfigUDP_TASK_STACK_SIZE_WORDS
#error now called: ipconfigIP_TASK_STACK_SIZE_WORDS
#endif
#ifdef ipconfigDRIVER_INCLUDED_RX_IP_FILTERING
#error now called: ipconfigETHERNET_DRIVER_FILTERS_PACKETS
#endif
#ifdef ipconfigMAX_SEND_BLOCK_TIME_TICKS
#error now called: ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS
#endif
#ifdef ipconfigUSE_RECEIVE_CONNECT_CALLBACKS
#error now called: ipconfigUSE_CALLBACKS
#endif
#ifdef ipconfigNUM_NETWORK_BUFFERS
#error now called: ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS
#endif
#ifdef ipconfigTCP_HANG_PROT
#error now called: ipconfigTCP_HANG_PROTECTION
#endif
#ifdef ipconfigTCP_HANG_PROT_TIME
#error now called: ipconfigTCP_HANG_PROTECTION_TIME
#endif
#ifdef FreeRTOS_lprintf
#error now called: FreeRTOS_debug_printf
#endif
#if ( ipconfigEVENT_QUEUE_LENGTH < ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 ) )
#error The ipconfigEVENT_QUEUE_LENGTH parameter must be at least ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5
#endif
#if ( ipconfigNETWORK_MTU < 46 )
#error ipconfigNETWORK_MTU must be at least 46.
#endif
#ifdef ipconfigBUFFER_ALLOC_FIXED_SIZE
#error ipconfigBUFFER_ALLOC_FIXED_SIZE was dropped and replaced by a const value, declared in BufferAllocation[12].c
#endif
#ifdef ipconfigNIC_SEND_PASSES_DMA
#error now called: ipconfigZERO_COPY_TX_DRIVER
#endif
#ifdef HAS_TX_CRC_OFFLOADING
/* _HT_ As these macro names have changed, throw an error
* if they're still defined. */
#error now called: ipconfigHAS_TX_CRC_OFFLOADING
#endif
#ifdef HAS_RX_CRC_OFFLOADING
#error now called: ipconfigHAS_RX_CRC_OFFLOADING
#endif
#ifdef ipconfigTCP_RX_BUF_LEN
#error ipconfigTCP_RX_BUF_LEN is now called ipconfigTCP_RX_BUFFER_LENGTH
#endif
#ifdef ipconfigTCP_TX_BUF_LEN
#error ipconfigTCP_TX_BUF_LEN is now called ipconfigTCP_TX_BUFFER_LENGTH
#endif
#ifdef ipconfigDHCP_USES_USER_HOOK
#error ipconfigDHCP_USES_USER_HOOK and its associated callback have been superseded - see http: /*www.FreeRTOS.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/TCP_IP_Configuration.html#ipconfigUSE_DHCP_HOOK */
#endif
#ifndef ipconfigUSE_TCP
#define ipconfigUSE_TCP ( 1 )
#endif
#if ipconfigUSE_TCP
/* Include support for TCP scaling windows */
#ifndef ipconfigUSE_TCP_WIN
#define ipconfigUSE_TCP_WIN ( 1 )
#endif
#ifndef ipconfigTCP_WIN_SEG_COUNT
#define ipconfigTCP_WIN_SEG_COUNT ( 256 )
#endif
#ifndef ipconfigIGNORE_UNKNOWN_PACKETS
/* When non-zero, TCP will not send RST packets in reply to
* TCP packets which are unknown, or out-of-order. */
#define ipconfigIGNORE_UNKNOWN_PACKETS ( 0 )
#endif
#endif /* if ipconfigUSE_TCP */
/*
* For debugging/logging: check if the port number is used for telnet
* Some events will not be logged for telnet connections
* because it would produce logging about the transmission of the logging...
* This macro will only be used if FreeRTOS_debug_printf() is defined for logging
*/
#ifndef ipconfigTCP_MAY_LOG_PORT
#define ipconfigTCP_MAY_LOG_PORT( xPort ) ( ( xPort ) != 23U )
#endif
#ifndef ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME
#define ipconfigSOCK_DEFAULT_RECEIVE_BLOCK_TIME portMAX_DELAY
#endif
#ifndef ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME
#define ipconfigSOCK_DEFAULT_SEND_BLOCK_TIME portMAX_DELAY
#endif
#ifndef ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS
#define ipconfigDNS_RECEIVE_BLOCK_TIME_TICKS pdMS_TO_TICKS( 5000U )
#endif
#ifndef ipconfigDNS_SEND_BLOCK_TIME_TICKS
#define ipconfigDNS_SEND_BLOCK_TIME_TICKS pdMS_TO_TICKS( 500U )
#endif
/*
* FreeRTOS debug logging routine (proposal)
* The macro will be called in the printf() style. Users can define
* their own logging routine as:
*
* #define FreeRTOS_debug_printf( MSG ) my_printf MSG
*
* The FreeRTOS_debug_printf() must be thread-safe but does not have to be
* interrupt-safe.
*/
#ifdef ipconfigHAS_DEBUG_PRINTF
#if ( ipconfigHAS_DEBUG_PRINTF == 0 )
#ifdef FreeRTOS_debug_printf
#error Do not define FreeRTOS_debug_print if ipconfigHAS_DEBUG_PRINTF is set to 0
#endif /* ifdef FreeRTOS_debug_printf */
#endif /* ( ipconfigHAS_DEBUG_PRINTF == 0 ) */
#endif /* ifdef ipconfigHAS_DEBUG_PRINTF */
#ifndef FreeRTOS_debug_printf
#define FreeRTOS_debug_printf( MSG ) do {} while( ipFALSE_BOOL )
#define ipconfigHAS_DEBUG_PRINTF 0
#endif
/*
* FreeRTOS general logging routine (proposal)
* Used in some utility functions such as FreeRTOS_netstat() and FreeRTOS_PrintARPCache()
*
* #define FreeRTOS_printf( MSG ) my_printf MSG
*
* The FreeRTOS_printf() must be thread-safe but does not have to be interrupt-safe
*/
#ifdef ipconfigHAS_PRINTF
#if ( ipconfigHAS_PRINTF == 0 )
#ifdef FreeRTOS_printf
#error Do not define FreeRTOS_print if ipconfigHAS_PRINTF is set to 0
#endif /* ifdef FreeRTOS_debug_printf */
#endif /* ( ipconfigHAS_PRINTF == 0 ) */
#endif /* ifdef ipconfigHAS_PRINTF */
#ifndef FreeRTOS_printf
#define FreeRTOS_printf( MSG ) do {} while( ipFALSE_BOOL )
#define ipconfigHAS_PRINTF 0
#endif
/*
* In cases where a lot of logging is produced, FreeRTOS_flush_logging( )
* will be called to give the logging module a chance to flush the data
* An example of this is the netstat command, which produces many lines of logging
*/
#ifndef FreeRTOS_flush_logging
#define FreeRTOS_flush_logging() do {} while( ipFALSE_BOOL )
#endif
/* Malloc functions. Within most applications of FreeRTOS, the couple
* pvPortMalloc()/vPortFree() will be used.
* If there is also SDRAM, the user may decide to use a different memory
* allocator:
* MallocLarge is used to allocate large TCP buffers (for Rx/Tx)
* MallocSocket is used to allocate the space for the sockets
*/
#ifndef pvPortMallocLarge
#define pvPortMallocLarge( x ) pvPortMalloc( x )
#endif
#ifndef vPortFreeLarge
#define vPortFreeLarge( ptr ) vPortFree( ptr )
#endif
#ifndef pvPortMallocSocket
#define pvPortMallocSocket( x ) pvPortMalloc( x )
#endif
#ifndef vPortFreeSocket
#define vPortFreeSocket( ptr ) vPortFree( ptr )
#endif
/*
* At several places within the library, random numbers are needed:
* - DHCP: For creating a DHCP transaction number
* - TCP: Set the Initial Sequence Number: this is the value of the first outgoing
* sequence number being used when connecting to a peer.
* Having a well randomized ISN is important to avoid spoofing
* - UDP/TCP: for setting the first port number to be used, in case a socket
* uses a 'random' or anonymous port number
*/
#ifndef ipconfigRAND32
#define ipconfigRAND32() rand()
#endif
/* --------------------------------------------------------
* End of: HT Added some macro defaults for the PLUS-UDP project
* -------------------------------------------------------- */
#ifndef ipconfigUSE_NETWORK_EVENT_HOOK
#define ipconfigUSE_NETWORK_EVENT_HOOK 0
#endif
#ifndef ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS
#define ipconfigUDP_MAX_SEND_BLOCK_TIME_TICKS ( pdMS_TO_TICKS( 20U ) )
#endif
#ifndef ipconfigARP_CACHE_ENTRIES
#define ipconfigARP_CACHE_ENTRIES 10
#endif
#ifndef ipconfigMAX_ARP_RETRANSMISSIONS
#define ipconfigMAX_ARP_RETRANSMISSIONS ( 5U )
#endif
#ifndef ipconfigMAX_ARP_AGE
#define ipconfigMAX_ARP_AGE 150U
#endif
#ifndef ipconfigUSE_ARP_REVERSED_LOOKUP
#define ipconfigUSE_ARP_REVERSED_LOOKUP 0
#endif
#ifndef ipconfigUSE_ARP_REMOVE_ENTRY
#define ipconfigUSE_ARP_REMOVE_ENTRY 0
#endif
#ifndef ipconfigINCLUDE_FULL_INET_ADDR
#define ipconfigINCLUDE_FULL_INET_ADDR 1
#endif
#ifndef ipconfigUSE_LINKED_RX_MESSAGES
#define ipconfigUSE_LINKED_RX_MESSAGES 0
#endif
#ifndef ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS
#define ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS 45
#endif
#ifndef ipconfigEVENT_QUEUE_LENGTH
#define ipconfigEVENT_QUEUE_LENGTH ( ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS + 5 )
#endif
#ifndef ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND
#define ipconfigALLOW_SOCKET_SEND_WITHOUT_BIND 1
#endif
/* Configuration to control whether packets with IP options,
* received over the network, should be passed up to the
* software stack OR should be dropped.
* If set to 1, the stack accepts IP packets that contain IP options, but does
* not process the options (IP options are not supported).
* If set to 0, the stack will drop IP packets that contain IP options.
*/
#ifndef ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS
#define ipconfigIP_PASS_PACKETS_WITH_IP_OPTIONS 1
#endif
/* Configuration to control whether UDP packets with
* checksum value of zero should be passed up the software
* stack OR should be dropped.
* If set to 1, the stack will accept UDP packets that have their checksum
* value set to 0.
* If set to 0, the stack will drop UDP packets that have their checksum value
* set to 0.
*/
#ifndef ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS
#define ipconfigUDP_PASS_ZERO_CHECKSUM_PACKETS 0
#endif
#ifndef ipconfigUDP_TIME_TO_LIVE
#define ipconfigUDP_TIME_TO_LIVE 128
#endif
#ifndef ipconfigTCP_TIME_TO_LIVE
#define ipconfigTCP_TIME_TO_LIVE 128
#endif
#ifndef ipconfigUDP_MAX_RX_PACKETS
/* Make positive to define the maximum number of packets which will be buffered
* for each UDP socket.
* Can be overridden with the socket option FREERTOS_SO_UDP_MAX_RX_PACKETS
*/
#define ipconfigUDP_MAX_RX_PACKETS 0U
#endif
#ifndef ipconfigUSE_DHCP
#define ipconfigUSE_DHCP 1
#endif
#ifndef ipconfigUSE_DHCP_HOOK
#define ipconfigUSE_DHCP_HOOK 0
#endif
#ifndef ipconfigDHCP_FALL_BACK_AUTO_IP
/*
* Only applicable when DHCP is in use:
* If no DHCP server responds, use "Auto-IP" : the
* device will allocate a random LinkLayer IP address.
*/
#define ipconfigDHCP_FALL_BACK_AUTO_IP ( 0 )
#endif
#if ( ipconfigDHCP_FALL_BACK_AUTO_IP != 0 )
#define ipconfigARP_USE_CLASH_DETECTION 1
#endif
#ifndef ipconfigARP_USE_CLASH_DETECTION
#define ipconfigARP_USE_CLASH_DETECTION 0
#endif
#ifndef ipconfigNETWORK_MTU
#define ipconfigNETWORK_MTU 1500
#else
#if ipconfigNETWORK_MTU > ( SIZE_MAX >> 1 )
#undef ipconfigNETWORK_MTU
#define ipconfigNETWORK_MTU ( SIZE_MAX >> 1 )
#endif
#endif
#ifndef ipconfigTCP_MSS
#define ipconfigTCP_MSS ( ipconfigNETWORK_MTU - ( ipSIZE_OF_IPv4_HEADER + ipSIZE_OF_TCP_HEADER ) )
#endif
/* Each TCP socket has circular stream buffers for Rx and Tx, which
* have a fixed maximum size.
* The defaults for these size are defined here, although
* they can be overridden at runtime by using the setsockopt() call */
#ifndef ipconfigTCP_RX_BUFFER_LENGTH
#define ipconfigTCP_RX_BUFFER_LENGTH ( 4U * ipconfigTCP_MSS ) /* defaults to 5840 bytes */
#endif
/* Define the size of Tx stream buffer for TCP sockets */
#ifndef ipconfigTCP_TX_BUFFER_LENGTH
#define ipconfigTCP_TX_BUFFER_LENGTH ( 4U * ipconfigTCP_MSS ) /* defaults to 5840 bytes */
#endif
#ifndef ipconfigMAXIMUM_DISCOVER_TX_PERIOD
#ifdef _WINDOWS_
#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( pdMS_TO_TICKS( 999U ) )
#else
#define ipconfigMAXIMUM_DISCOVER_TX_PERIOD ( pdMS_TO_TICKS( 30000U ) )
#endif /* _WINDOWS_ */
#endif /* ipconfigMAXIMUM_DISCOVER_TX_PERIOD */
#if ( ipconfigUSE_DNS == 0 )
/* The DNS module will not be included. */
#if ( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) )
/* LLMNR and NBNS depend on DNS because those protocols share a lot of code. */
#error When either LLMNR or NBNS is used, ipconfigUSE_DNS must be defined
#endif
#endif
#ifndef ipconfigUSE_DNS
#define ipconfigUSE_DNS 1
#endif
#ifndef ipconfigDNS_REQUEST_ATTEMPTS
#define ipconfigDNS_REQUEST_ATTEMPTS 5
#endif
#ifndef ipconfigUSE_DNS_CACHE
#define ipconfigUSE_DNS_CACHE 0
#endif
#if ( ipconfigUSE_DNS_CACHE != 0 )
#ifndef ipconfigDNS_CACHE_NAME_LENGTH
/* Per https://tools.ietf.org/html/rfc1035, 253 is the maximum string length
* of a DNS name. The following default accounts for a null terminator. */
#define ipconfigDNS_CACHE_NAME_LENGTH 254U
#endif
#ifndef ipconfigDNS_CACHE_ENTRIES
#define ipconfigDNS_CACHE_ENTRIES 1
#endif
#endif /* ipconfigUSE_DNS_CACHE != 0 */
/* When accessing services which have multiple IP addresses, setting this
* greater than 1 can improve reliability by returning different IP address
* answers on successive calls to FreeRTOS_gethostbyname(). */
#ifndef ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY
#define ipconfigDNS_CACHE_ADDRESSES_PER_ENTRY 1
#endif
#ifndef ipconfigCHECK_IP_QUEUE_SPACE
#define ipconfigCHECK_IP_QUEUE_SPACE 0
#endif
#ifndef ipconfigUSE_LLMNR
/* Include support for LLMNR: Link-local Multicast Name Resolution (non-Microsoft) */
#define ipconfigUSE_LLMNR ( 0 )
#endif
#ifndef ipconfigREPLY_TO_INCOMING_PINGS
#define ipconfigREPLY_TO_INCOMING_PINGS 1
#endif
#ifndef ipconfigSUPPORT_OUTGOING_PINGS
#define ipconfigSUPPORT_OUTGOING_PINGS 1
#endif
#ifndef ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES
#define ipconfigFILTER_OUT_NON_ETHERNET_II_FRAMES 1
#endif
#ifndef ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES
#define ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES 1
#endif
#ifndef configINCLUDE_TRACE_RELATED_CLI_COMMANDS
#define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS 0
#else
#define ipconfigINCLUDE_EXAMPLE_FREERTOS_PLUS_TRACE_CALLS configINCLUDE_TRACE_RELATED_CLI_COMMANDS
#endif
#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM ( 0 )
#endif
#ifndef ipconfigETHERNET_DRIVER_FILTERS_PACKETS
#define ipconfigETHERNET_DRIVER_FILTERS_PACKETS ( 0 )
#endif
#ifndef ipconfigWATCHDOG_TIMER
/* This macro will be called in every loop the IP-task makes. It may be
* replaced by user-code that triggers a watchdog */
#define ipconfigWATCHDOG_TIMER()
#endif
#ifndef ipconfigUSE_CALLBACKS
#define ipconfigUSE_CALLBACKS ( 0 )
#endif
#if ( ipconfigUSE_CALLBACKS != 0 )
#ifndef ipconfigIS_VALID_PROG_ADDRESS
/* Replace this macro with a test returning non-zero if the memory pointer to by x
* is valid memory which can contain executable code
* In fact this is an extra safety measure: if a handler points to invalid memory,
* it will not be called
*/
#define ipconfigIS_VALID_PROG_ADDRESS( x ) ( ( x ) != NULL )
#endif
#endif
#ifndef ipconfigHAS_INLINE_FUNCTIONS
#define ipconfigHAS_INLINE_FUNCTIONS ( 1 )
#endif
#ifndef portINLINE
#define portINLINE inline
#endif
#ifndef ipconfigZERO_COPY_TX_DRIVER
/* When non-zero, the buffers passed to the SEND routine may be passed
* to DMA. As soon as sending is ready, the buffers must be released by
* calling vReleaseNetworkBufferAndDescriptor(), */
#define ipconfigZERO_COPY_TX_DRIVER ( 0 )
#endif
#ifndef ipconfigZERO_COPY_RX_DRIVER
/* This define doesn't mean much to the driver, except that it makes
* sure that pxPacketBuffer_to_NetworkBuffer() will be included. */
#define ipconfigZERO_COPY_RX_DRIVER ( 0 )
#endif
#ifndef ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM
#define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 0
#endif
#ifndef ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM
#define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 0
#endif
#ifndef ipconfigDHCP_REGISTER_HOSTNAME
#define ipconfigDHCP_REGISTER_HOSTNAME 0
#endif
#ifndef ipconfigSOCKET_HAS_USER_SEMAPHORE
#define ipconfigSOCKET_HAS_USER_SEMAPHORE 0
#endif
#ifndef ipconfigSOCKET_HAS_USER_WAKE_CALLBACK
#define ipconfigSOCKET_HAS_USER_WAKE_CALLBACK 0
#endif
#ifndef ipconfigSUPPORT_SELECT_FUNCTION
#define ipconfigSUPPORT_SELECT_FUNCTION 0
#endif
#ifndef ipconfigTCP_KEEP_ALIVE
#define ipconfigTCP_KEEP_ALIVE 0
#endif
#ifndef ipconfigDNS_USE_CALLBACKS
#define ipconfigDNS_USE_CALLBACKS 0
#endif
#ifndef ipconfigSUPPORT_SIGNALS
#define ipconfigSUPPORT_SIGNALS 0
#endif
#ifndef ipconfigUSE_NBNS
#define ipconfigUSE_NBNS 0
#endif
/* As an attack surface reduction for ports that listen for inbound
* connections, hang protection can help reduce the impact of SYN floods. */
#ifndef ipconfigTCP_HANG_PROTECTION
#define ipconfigTCP_HANG_PROTECTION 1
#endif
/* Non-activity timeout is expressed in seconds. */
#ifndef ipconfigTCP_HANG_PROTECTION_TIME
#define ipconfigTCP_HANG_PROTECTION_TIME 30U
#endif
#ifndef ipconfigTCP_IP_SANITY
#define ipconfigTCP_IP_SANITY 0
#endif
#ifndef ipconfigARP_STORES_REMOTE_ADDRESSES
#define ipconfigARP_STORES_REMOTE_ADDRESSES 0
#endif
#ifndef ipconfigBUFFER_PADDING
/* Expert option: define a value for 'ipBUFFER_PADDING'.
* When 'ipconfigBUFFER_PADDING' equals 0,
* 'ipBUFFER_PADDING' will get a default value of 8 + 2 bytes. */
#define ipconfigBUFFER_PADDING 0U
#endif
#ifndef ipconfigPACKET_FILLER_SIZE
#define ipconfigPACKET_FILLER_SIZE 2U
#endif
#ifndef ipconfigSELECT_USES_NOTIFY
#define ipconfigSELECT_USES_NOTIFY 0
#endif
#endif /* FREERTOS_DEFAULT_IP_CONFIG_H */

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