summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/FreeRTOS_Stream_Buffer.c
blob: 0bda99317f12974e4584c36892a2449f1cf94fd1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/*
 * FreeRTOS+TCP V2.2.0
 * 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
 */

/* 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"

/*
 * uxStreamBufferAdd( )
 * Adds data to a stream buffer.  If uxOffset > 0, data will be written at
 * an offset from uxHead while uxHead will not be moved yet.  This possibility
 * will be used when TCP data is received while earlier data is still missing.
 * If 'pucData' equals NULL, the function is called to advance 'uxHead' only.
 */
size_t uxStreamBufferAdd( StreamBuffer_t *pxBuffer, size_t uxOffset, const uint8_t *pucData, size_t uxCount )
{
size_t uxSpace, uxNextHead, uxFirst;

	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. */
			memcpy( ( void* ) ( 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. */
				memcpy( ( void * )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;
}
/*-----------------------------------------------------------*/

/*
 * uxStreamBufferGet( )
 * 'uxOffset' can be used to read data located at a certain offset from 'lTail'.
 * If 'pucData' equals NULL, the function is called to advance 'lTail' only.
 * if 'xPeek' is pdTRUE, or if 'uxOffset' is non-zero, the 'lTail' pointer will
 * not be advanced.
 */
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. */
			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. */
				memcpy( pucData + uxFirst, pxBuffer->ucArray, uxCount - uxFirst );
			}
		}

		if( ( xPeek == pdFALSE ) && ( uxOffset == 0UL ) )
		{
			/* Move the tail pointer to effecively remove the data read from
			the buffer. */
			uxNextTail += uxCount;

			if( uxNextTail >= pxBuffer->LENGTH )
			{
				uxNextTail -= pxBuffer->LENGTH;
			}

			pxBuffer->uxTail = uxNextTail;
		}
	}

	return uxCount;
}