事件标志组实现原理源码分析

事件标志组控制块

 


	
	#define eventCLEAR_EVENTS_ON_EXIT_BIT	0x01000000UL		//表示退出是否清楚已经触发的标志位 25bit表示
	#define eventUNBLOCKED_DUE_TO_BIT_SET	0x02000000UL		//解除阻塞是否,已经设置标志位 26位
	#define eventWAIT_FOR_ALL_BITS			0x04000000UL		//是与逻辑还是或逻辑
	#define eventEVENT_BITS_CONTROL_BYTES	0xff000000UL		//用于分解出,事件标志组位使用

typedef struct xEventGroupDefinition
{
	//事件标志组
	EventBits_t uxEventBits;
	//任务等待的列表
	List_t xTasksWaitingForBits;		/*< List of tasks waiting for a bit to be set. */
} EventGroup_t;

EventGetBit

#define xEventGroupGetBits( xEventGroup ) xEventGroupClearBits( xEventGroup, 0 )

/*
	参数:
	1、控制块/句柄
	2、要清除位
	返回值:
		事件标志位

*/ 1<<0
EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;

	/*
		1、进入临界段
		2、获取当前事件标志位
		3、清除要设置的事件标志位
		4、退出临界段
		5、返回事件标志组值
	
	*/
	taskENTER_CRITICAL();
	{

		/* The value returned is the event group value prior to the bits being
		cleared. */
		uxReturn = pxEventBits->uxEventBits;

		/* Clear the bits. */
		pxEventBits->uxEventBits &= ~uxBitsToClear;
	}
	taskEXIT_CRITICAL();

	return uxReturn;
}

/*
	参数:	
		1、事件控制块
	返回值:
		事件标志位

*/
EventBits_t xEventGroupGetBitsFromISR( EventGroupHandle_t xEventGroup )
{
UBaseType_t uxSavedInterruptStatus;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn;
	
	//禁止中断 带返回值
	uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
	{
		//获取事件标志位
		uxReturn = pxEventBits->uxEventBits;
	}
	//恢复中断,在进入禁止之前的状态
	portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

	return uxReturn;
}

xEventGroupWaitBits

/*
	参数:
		1、事件控制块
		2、要等待出发的标志位
		3、退出是否要清除
		4、与逻辑还是或逻辑
		5、阻塞等待时间
	返回值:
		当前事件标志位
*/
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, 
								const EventBits_t uxBitsToWaitFor, 
								const BaseType_t xClearOnExit, 
								const BaseType_t xWaitForAllBits, 
								TickType_t xTicksToWait )
{
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
EventBits_t uxReturn, uxControlBits = 0;
BaseType_t xWaitConditionMet, xAlreadyYielded;
BaseType_t xTimeoutOccurred = pdFALSE;
	//挂起调度器
	vTaskSuspendAll();
	{
		//获取当前的事件标志位
		const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits;

		/* 检查是否触发 
			参数:	
				1、当前的事件标志位
				2、要等待触发的事件标志位
				3、触发逻辑???
			返回值:	
				pdFALSE  pdTRUE
		*/
		xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits );

		if( xWaitConditionMet != pdFALSE )
		{
			
			/* 已经触发 */
			uxReturn = uxCurrentEventBits;
			xTicksToWait = ( TickType_t ) 0;

			/* 清楚已经触发的标志 */
			if( xClearOnExit != pdFALSE )
			{
				pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		else if( xTicksToWait == ( TickType_t ) 0 )
		{
			/* 不需要超时,直接返回标志位. */
			uxReturn = uxCurrentEventBits;
		}
		else
		{
			/* 事件没有触发,并且需要超时*/
			if( xClearOnExit != pdFALSE )
			{
				//uxControlBits = 0x01000000UL;
				uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			if( xWaitForAllBits != pdFALSE )
			{
				//uxControlBits = 0x05000000UL;
				uxControlBits |= eventWAIT_FOR_ALL_BITS;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			/* 把任务添加到事件列表中
				参数:
					1、列表的地址
					2、传入列表项值
					3、任务阻塞时间

			*/
			vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait );

			uxReturn = 0;

			traceEVENT_GROUP_WAIT_BITS_BLOCK( xEventGroup, uxBitsToWaitFor );
		}
	}
	//恢复调度器
	xAlreadyYielded = xTaskResumeAll();
	//再次判断是否需要超时
	if( xTicksToWait != ( TickType_t ) 0 )
	{
		if( xAlreadyYielded == pdFALSE )
		{
			//进行上下文切换 ->pendSV
			portYIELD_WITHIN_API();
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}

		/* 
			任务已经恢复
			1、复位列表项中的值  复位为任务有优先级
		*/
		uxReturn = uxTaskResetEventItemValue();
		//是不是通过事件置位解除的任务
		if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 )
		{
			//进入临界段
			taskENTER_CRITICAL();
			{
				/* 获取当前事件位. */
				uxReturn = pxEventBits->uxEventBits;

				/* 再此判断是否已经置位 */
				if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE )
				{
					//如果需要清除,清除触发后的标志位
					if( xClearOnExit != pdFALSE )
					{
						pxEventBits->uxEventBits &= ~uxBitsToWaitFor;
					}
					else
					{
						mtCOVERAGE_TEST_MARKER();
					}
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			taskEXIT_CRITICAL();
			xTimeoutOccurred = pdFALSE;
		}
		else
		{
			/* The task unblocked because the bits were set. */
		}

		/* 返回当前事件标志位. */
		uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES;
	}
	traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxBitsToWaitFor, xTimeoutOccurred );

	return uxReturn;
}

xEventGroupSetBits

/*
	参数:
		1、事件控制块
		2、要设置的事件位
	返回值:
		1、当前事件标志位
*/
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
ListItem_t *pxListItem, *pxNext;
ListItem_t const *pxListEnd;
List_t *pxList;
EventBits_t uxBitsToClear = 0, uxBitsWaitedFor, uxControlBits;
EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
BaseType_t xMatchFound = pdFALSE;

	//获取事件列表头
	pxList = &( pxEventBits->xTasksWaitingForBits );
	//获取列表尾节点
	pxListEnd = listGET_END_MARKER( pxList ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM.  This is checked and valid. */
	//挂起调度器
	vTaskSuspendAll();
	{
		//获取头节点
		pxListItem = listGET_HEAD_ENTRY( pxList );

		/* 设置事件标志位 */
		pxEventBits->uxEventBits |= uxBitsToSet;

		/* 循环遍历整个列表项,直到列表头节点等于尾节点(指针) */
		while( pxListItem != pxListEnd )
		{
			//获取下个列表项
			pxNext = listGET_NEXT( pxListItem );
			//获取当前列表项的值
			uxBitsWaitedFor = listGET_LIST_ITEM_VALUE( pxListItem );
			//标记,是否找到需要处理的节点
			xMatchFound = pdFALSE;

			/* 拆分*/
			uxControlBits = uxBitsWaitedFor & eventEVENT_BITS_CONTROL_BYTES;
			uxBitsWaitedFor &= ~eventEVENT_BITS_CONTROL_BYTES;

			if( ( uxControlBits & eventWAIT_FOR_ALL_BITS ) == ( EventBits_t ) 0 )
			{
				//或逻辑
				/* 等待位已经置位 */
				if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) != ( EventBits_t ) 0 )
				{
					//找到了已经触发的节点
					xMatchFound = pdTRUE;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			//表示所有等待的位都已经触发
			else if( ( uxBitsWaitedFor & pxEventBits->uxEventBits ) == uxBitsWaitedFor )
			{
				/*找到触发的节点 */
				xMatchFound = pdTRUE;
			}
			else
			{
				/* Need all bits to be set, but not all the bits were set. */
			}

			if( xMatchFound != pdFALSE )
			{
				/* 是否需要清除 */
				if( ( uxControlBits & eventCLEAR_EVENTS_ON_EXIT_BIT ) != ( EventBits_t ) 0 )
				{
					//做个标记
					uxBitsToClear |= uxBitsWaitedFor;
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}

				/* 把任务从事件列表中移除
					参数:	
						1、列表项
						2、事件标志位+解锁处理标志位  内部写入了列表项的value里面

				*/
				( void ) xTaskRemoveFromUnorderedEventList( pxListItem, pxEventBits->uxEventBits | eventUNBLOCKED_DUE_TO_BIT_SET );
			}

			/* 当前列表项指向下个,继续遍历*/
			pxListItem = pxNext;
		}

		/* 清除设置后的标志位 */
		pxEventBits->uxEventBits &= ~uxBitsToClear;
	}
	//开启调度器
	( void ) xTaskResumeAll();

	return pxEventBits->uxEventBits;
}

	/*
		参数:
		1、事件控制块
		2、要设置的标志位
		3、NULL
	*/
	BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, BaseType_t *pxHigherPriorityTaskWoken )
	{
	BaseType_t xReturn;
		//调用软件定时器函数,,用于发送消息到软件定时器任务,进行处理
		xReturn = xTimerPendFunctionCallFromISR( vEventGroupSetBitsCallback, ( void * ) xEventGroup, ( uint32_t ) uxBitsToSet, pxHigherPriorityTaskWoken );

		return xReturn;
	}
	/*
		设置事件标志位的回调函数,内部其实就是调用xEventGroupSetBits
	*/
	void vEventGroupSetBitsCallback( void *pvEventGroup, const uint32_t ulBitsToSet )
	{
	( void ) xEventGroupSetBits( pvEventGroup, ( EventBits_t ) ulBitsToSet );
	}
	
	BaseType_t xTimerPendFunctionCallFromISR( PendedFunction_t xFunctionToPend, void *pvParameter1, uint32_t ulParameter2, BaseType_t *pxHigherPriorityTaskWoken )
	{
	DaemonTaskMessage_t xMessage;
	BaseType_t xReturn;

		/* 封装消息 */
		xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
		xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
		xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
		xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
		//通过消息队列和软件定时器任务进行通信
		xReturn = xQueueSendFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
		/*
			分析:
				软件定时器任务要等待消息队列,之后解析处理,最终调用xEventGroupSetBits
		
		*/

		return xReturn;
	}

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值