学习一下freertos streambuffer

学习一下freertos stream buffer

最近在自己从0到1写rtos,主要是为了学习rtos,并没有其他卵用,光学会调API是不够的,看源码又恼火,所以学习的最好办法还是根据自己的理解自己动手撸代码,虽然大部分思路都是抄的freertos或者rt thread(主要是抄思路,代码还是自己按理解写的),抄完调通的时候rtos也就基本掌握了。

  • 废话不多说,直接分析代码吧,先从StreamBuffer_t这个控制块或者说handle
    说起。
typedef struct StreamBufferDef_t /*lint !e9058 Style convention uses tag. */
{
	volatile size_t xTail;				/* 相当于队列尾部,从这取数据. */
	volatile size_t xHead;				/* 队列头,从这个地址存数据. */
	size_t xLength;						/* The length of the buffer pointed to by pucBuffer. */
	size_t xTriggerLevelBytes;			/* 存多少个bytes数据后通知消费者来取. */
	volatile TaskHandle_t xTaskWaitingToReceive; /* 因为接收失败而挂起的任务,由于是一对一的方式,所以不需要链表 */
	volatile TaskHandle_t xTaskWaitingToSend;	/*同上 */
	uint8_t *pucBuffer;					/* 存放数据的内存*/
	uint8_t ucFlags;
} StreamBuffer_t;
  • 接下来就是喜闻乐见的分析xStreamBufferGenericCreateStatic这个函数了,因为我通常用静态内存分配,所以是这个函数。
StreamBufferHandle_t xStreamBufferGenericCreateStatic( size_t xBufferSizeBytes,
														   size_t xTriggerLevelBytes,
														   BaseType_t xIsMessageBuffer,
														   uint8_t * const pucStreamBufferStorageArea,
														   StaticStreamBuffer_t * const pxStaticStreamBuffer )
	{
	StreamBuffer_t * const pxStreamBuffer = ( StreamBuffer_t * ) pxStaticStreamBuffer; /*lint !e740 !e9087 Safe cast as StaticStreamBuffer_t is opaque Streambuffer_t. */
	StreamBufferHandle_t xReturn;
	uint8_t ucFlags;
  • StaticStreamBuffer_t StreamBuffer_t 其实是一样的(自己跳转看定义),StreamBufferHandle_t是上面两个的指针,不知道freertos搞这么多定义干什么,跳来跳去,一点也不干净。
if( xTriggerLevelBytes == ( size_t ) 0 )
		{
			xTriggerLevelBytes = ( size_t ) 1;
		}

		if( xIsMessageBuffer != pdFALSE )
		{
			/* Statically allocated message buffer. */
			ucFlags = sbFLAGS_IS_MESSAGE_BUFFER | sbFLAGS_IS_STATICALLY_ALLOCATED;
		}
		else
		{
			/* Statically allocated stream buffer. */
			ucFlags = sbFLAGS_IS_STATICALLY_ALLOCATED;
		}
  • 其实这里还可以搞成message buffer,根据传入的参数xIsMessageBuffer不同而复用。
configASSERT( xBufferSizeBytes > sbBYTES_TO_STORE_MESSAGE_LENGTH );
  • 如果是message buffer,每条消息大小不能小于4bytes。
if( ( pucStreamBufferStorageArea != NULL ) && ( pxStaticStreamBuffer != NULL ) )
		{
			prvInitialiseNewStreamBuffer( pxStreamBuffer,
										  pucStreamBufferStorageArea,
										  xBufferSizeBytes,
										  xTriggerLevelBytes,
										  ucFlags );

			/* Remember this was statically allocated in case it is ever deleted
			again. */
			pxStreamBuffer->ucFlags |= sbFLAGS_IS_STATICALLY_ALLOCATED;

			traceSTREAM_BUFFER_CREATE( pxStreamBuffer, xIsMessageBuffer );

			xReturn = ( StreamBufferHandle_t ) pxStaticStreamBuffer; /*lint !e9087 Data hiding requires cast to opaque type. */
		}
		else
		{
			xReturn = NULL;
			traceSTREAM_BUFFER_CREATE_STATIC_FAILED( xReturn, xIsMessageBuffer );
		}

		return xReturn;
	}
  • 实际上是调用prvInitialiseNewStreamBuffer进行真正的stream buffer(message buf)初始化。
static void prvInitialiseNewStreamBuffer( StreamBuffer_t * const pxStreamBuffer,
										  uint8_t * const pucBuffer,
										  size_t xBufferSizeBytes,
										  size_t xTriggerLevelBytes,
										  uint8_t ucFlags )
{
	/* Assert here is deliberately writing to the entire buffer to ensure it can
	be written to without generating exceptions, and is setting the buffer to a
	known value to assist in development/debugging. */
	#if( configASSERT_DEFINED == 1 )
	{
		/* The value written just has to be identifiable when looking at the
		memory.  Don't use 0xA5 as that is the stack fill value and could
		result in confusion as to what is actually being observed. */
		const BaseType_t xWriteValue = 0x55;
		configASSERT( memset( pucBuffer, ( int ) xWriteValue, xBufferSizeBytes ) == pucBuffer );
	} /*lint !e529 !e438 xWriteValue is only used if configASSERT() is defined. */
	#endif

	( void ) memset( ( void * ) pxStreamBuffer, 0x00, sizeof( StreamBuffer_t ) ); /*lint !e9087 memset() requires void *. */
	pxStreamBuffer->pucBuffer = pucBuffer;
	pxStreamBuffer->xLength = xBufferSizeBytes;
	pxStreamBuffer->xTriggerLevelBytes = xTriggerLevelBytes;
	pxStreamBuffer->ucFlags = ucFlags;
}
  • 就是给结构体赋值,注意一下pucBuffer是正真存储数据的内存,应该是个uint8_t 或者void *指针。
BaseType_t xStreamBufferReset( StreamBufferHandle_t xStreamBuffer )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
BaseType_t xReturn = pdFAIL;

#if( configUSE_TRACE_FACILITY == 1 )
	UBaseType_t uxStreamBufferNumber;
#endif

	configASSERT( pxStreamBuffer );

	#if( configUSE_TRACE_FACILITY == 1 )
	{
		/* Store the stream buffer number so it can be restored after the
		reset. */
		uxStreamBufferNumber = pxStreamBuffer->uxStreamBufferNumber;
	}
	#endif

	/* Can only reset a message buffer if there are no tasks blocked on it. */
	taskENTER_CRITICAL();
	{
		if( pxStreamBuffer->xTaskWaitingToReceive == NULL )
		{
			if( pxStreamBuffer->xTaskWaitingToSend == NULL )
			{
				prvInitialiseNewStreamBuffer( pxStreamBuffer,
											  pxStreamBuffer->pucBuffer,
											  pxStreamBuffer->xLength,
											  pxStreamBuffer->xTriggerLevelBytes,
											  pxStreamBuffer->ucFlags );
				xReturn = pdPASS;

				#if( configUSE_TRACE_FACILITY == 1 )
				{
					pxStreamBuffer->uxStreamBufferNumber = uxStreamBufferNumber;
				}
				#endif

				traceSTREAM_BUFFER_RESET( xStreamBuffer );
			}
		}
	}
	taskEXIT_CRITICAL();

	return xReturn;
}
  • 重置stream buf, 仅当没有发送和接收任务阻塞在这个stream buf上时。
BaseType_t xStreamBufferSetTriggerLevel( StreamBufferHandle_t xStreamBuffer, size_t xTriggerLevel )
{
StreamBuffer_t * const pxStreamBuffer = xStreamBuffer;
BaseType_t xReturn;

	configASSERT( pxStreamBuffer );

	/* It is not valid for the trigger level to be 0. */
	if( xTriggerLevel == ( size_t ) 0 )
	{
		xTriggerLevel = ( size_t ) 1;
	}

	/* The trigger level is the number of bytes that must be in the stream
	buffer before a task that is waiting for data is unblocked. */
	if( xTriggerLevel <= pxStreamBuffer->xLength )
	{
		pxStreamBuffer->xTriggerLevelBytes = xTriggerLevel;
		xReturn = pdPASS;
	}
	else
	{
		xReturn = pdFALSE;
	}

	return xReturn;
}
  • 通过这里分析pxStreamBuffer->xLength应该是这个stream buf能存下的最大bytes数,xTriggerLevel就是说当达到多少个bytes后去通知挂起的任务(stream buffer都是用的通知的形式,所以基本上是用于一对一的任务同步用)。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOSStreamBuffer是一种用于在任务之间传输数据的机制。通过使用StreamBuffer,任务可以安全地发送和接收数据,而不需要使用信号量或队列。StreamBuffer的功能可以通过在构建中包含FreeRTOS/source/stream_buffer.c源文件来启用\[2\]。 在使用StreamBuffer时,可以使用一些关键函数来创建、发送和接收数据。例如,可以使用xStreamBufferCreate函数来创建一个StreamBuffer,并指定其大小\[1\]。要发送数据到StreamBuffer,可以使用xStreamBufferSend函数。而要从StreamBuffer接收数据,可以使用xStreamBufferReceive函数\[3\]。 在使用xStreamBufferReceive函数时,需要提供一个指向接收数据缓冲区的指针,以及缓冲区的长度。还可以指定一个等待时间,如果在指定的时间内没有可用的数据,则函数将等待直到有数据可用或超时\[3\]。 总之,FreeRTOSStreamBuffer提供了一种方便的方式来在任务之间传输数据。通过使用关键函数,可以创建、发送和接收数据,从而实现任务之间的通信。 #### 引用[.reference_title] - *1* [FreeRTOS学习笔记-Stream Buffer](https://blog.csdn.net/ai_ljh/article/details/126817128)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [FreeRTOSStream Buffers(流缓冲区)](https://blog.csdn.net/shallowing/article/details/117385089)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值