semphr.h文件

/*
    FreeRTOS V9.0.0 - Copyright (C) 2016 Real Time Engineers Ltd.
    All rights reserved
*/

#ifndef SEMAPHORE_H
#define SEMAPHORE_H

#ifndef INC_FREERTOS_H
    #error "include FreeRTOS.h" must appear in source files before "include semphr.h"
#endif

#include "queue.h"

typedef QueueHandle_t SemaphoreHandle_t;

#define semBINARY_SEMAPHORE_QUEUE_LENGTH    ( ( uint8_t ) 1U )
#define semSEMAPHORE_QUEUE_ITEM_LENGTH      ( ( uint8_t ) 0U )
#define semGIVE_BLOCK_TIME                  ( ( TickType_t ) 0U )
//----------------------------------------------------------------------------------
/** 创建二值信号量(有参,传递句柄)
 * <pre>vSemaphoreCreateBinary( SemaphoreHandle_t xSemaphore )</pre>

 * 用法例程:

 SemaphoreHandle_t xSemaphore = NULL;

 void vATask( void * pvParameters ) //任务函数入口
 {
    // 调用vSemaphoreCreateBinary ()之前,信号量无法使用
    // 这是一个宏,所以直接传入变量。
    vSemaphoreCreateBinary( xSemaphore );

    if( xSemaphore != NULL )
    {
        // 成功创建了信号量。
        // 现在可以使用信号量了。
    }
 }
 </pre>
 * \defgroup 创建二值信号量的API
 * \ingroup Semaphores
 */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define vSemaphoreCreateBinary( xSemaphore )                                                                                            \
        {                                                                                                                                   \
            ( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE );    \
            if( ( xSemaphore ) != NULL )                                                                                                    \
            {                                                                                                                               \
                ( void ) xSemaphoreGive( ( xSemaphore ) );                                                                                  \
            }                                                                                                                               \
        }
#endif

/** 创建二值信号量(无参,返回句柄)
 * SemaphoreHandle_t xSemaphoreCreateBinary( void )

 * Example usage:

 SemaphoreHandle_t xSemaphore = NULL;

 void vATask( void * pvParameters )
 {
    // 调用xSemaphoreCreateBinary()之前,信号量无法使用
    // 这是一个宏,所以直接传入变量。
    xSemaphore = xSemaphoreCreateBinary();

    if( xSemaphore != NULL )
    {
        // 成功创建了信号量。
        // 现在可以使用信号量了。
    }
 }
 * 这种类型的信号量可以用于任务或在中断和任务之间。
 */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif

/**
 * SemaphoreHandle_t xSemaphoreCreateBinaryStatic( StaticSemaphore_t *pxSemaphoreBuffer )
 * 静态创建一个新的二进制信号量实例,并返回一个句柄可以引用新的信号量。
 * 
 * Example usage:
 <pre>
 SemaphoreHandle_t xSemaphore = NULL;
 StaticSemaphore_t xSemaphoreBuffer;

 void vATask( void * pvParameters )
 {
    // 调用xSemaphoreCreateBinary()之前信号量无法使用
    // 信号量的数据结构将放在变量xSemaphoreBuffer中,它的地址被传递到函数中。
    // 函数的参数不是NULL,因此函数不会尝试任何值动态内存分配,因此函数不会返回。
    
    xSemaphore = xSemaphoreCreateBinary( &xSemaphoreBuffer );

    // 其余的任务代码放在这里。
 }
 */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
    #define xSemaphoreCreateBinaryStatic( pxStaticSemaphore ) xQueueGenericCreateStatic( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticSemaphore, queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif /* configSUPPORT_STATIC_ALLOCATION */



/**  在中断中获取一个信号量
 xSemaphoreTakeFromISR(
                          SemaphoreHandle_t xSemaphore,
                          BaseType_t *pxHigherPriorityTaskWoken
                      )
 *
 * 信号量必须是通过调用xsemaphorestatebinary()或xSemaphoreCreateCounting ()创建的。
 * 这个宏可以从ISR中使用,但是要从ISR中获取信号量,并不是常见的操作。互斥信号量不能在中断中使用!!!!
 *
 * @param xSemaphore 信号量句柄,这是创建信号量时返回的句柄。
 *
 * @param pxHigherPriorityTaskWoken :
 * xSemaphoreTakeFromISR()将把*pxHigherPriorityTaskWoken设置为pdTRUE,如果接收信号量导致任务解阻塞,并且解阻塞任务的优先级高于当前正在运行的任务。
 * 如果xSemaphoreTakeFromISR()将这个值设置为pdTRUE,那么应该在中断退出之前请求上下文切换。
 *
 */
#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )  xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )



/** 创建互斥信号量
 * SemaphoreHandle_t xSemaphoreCreateMutex( void )  //创建一个新的互斥类型信号量实例,并返回新的互斥量句柄。
 *
 * 在FreeRTOS实现内部,互斥信号量使用一个互斥体结构存储在其中的块内存, 如果使用xsemaphoreatemutex()创建互斥对象,则在xsemaphoreatemutex()函数中会动态分配自动生成所需的内存
 * 如果使用xsemaphoreatemutexstatic()创建互斥对象,那么应用程序编写器必须提供内存。 因此,xsemaphoreatemutexstatic()允许在不使用任何动态内存分配的情况下创建互斥体。
 *
 * 使用这个函数创建的互斥对象可以使用xSemaphoreTake()和xSemaphoreGive()宏访问。 
 * 不能使用xSemaphoreTakeRecursive()和xSemaphoreGiveRecursive()宏。
 * 
 * 这种类型的信号量使用优先级继承机制,因此当不再需要信号量时,“获取take”该信号量的任务必须始终“释放give”该信号量。
 * 互斥类型信号量不能从中断服务例程中使用。
 *
 * Example usage:

 SemaphoreHandle_t xSemaphore;

 void vATask( void * pvParameters )
 {
    // 在调用xsemaphoreatemutex()之前,不能使用信号量。
    // 这是一个宏,所以直接传入变量。
    xSemaphore = xSemaphoreCreateMutex();

    if( xSemaphore != NULL )
    {
        // 成功创建了信号量。
        // 现在可以使用信号量了。
    }
 }
 */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#endif

/**
 * 创建静态互斥信号量
 * SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )
 *
 * 创建一个新的互斥锁类型信号量实例,并返回一个句柄,通过该句柄可以引用新的互斥锁。
 *
 * 使用这个函数创建的互斥对象可以使用xSemaphoreTake()和xSemaphoreGive()宏访问。不能使用xSemaphoreTakeRecursive()和xSemaphoreGiveRecursive()宏。 
 * 这种类型的信号量使用优先级继承机制,因此当不再需要信号量时,“接收”该信号量的任务必须始终“返回”该信号量。
 *
 * 互斥类型信号量不能从中断服务例程中使用。
 *
 * Example usage:

 SemaphoreHandle_t xSemaphore;
 StaticSemaphore_t xMutexBuffer;

 void vATask( void * pvParameters )
 {
    // 互斥体在创建之前不能使用。静态创建不尝试动态内存分配。
    xSemaphore = xSemaphoreCreateMutexStatic( &xMutexBuffer );

    // 由于没有执行动态内存分配,xSemaphore不能为空,
    // 所以没有必要检查它。
 }

 */
 #if( configSUPPORT_STATIC_ALLOCATION == 1 )
    #define xSemaphoreCreateMutexStatic( pxMutexBuffer ) xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */


/**创建动态递归互斥信号量
 * SemaphoreHandle_t  xSemaphoreCreateRecursiveMutex( void )
 *
 * 创建一个新的递归互斥锁类型信号量实例,并返回一个句柄,通过该句柄可以引用新的递归互斥锁。
 *
 * 使用这个宏创建的互斥对象可以使用xSemaphoreTakeRecursive()和xSemaphoreGiveRecursive()宏访问。  
 * 不能使用xSemaphoreTake()和xSemaphoreGive()宏。
 *
 * 递归使用的互斥量可以由所有者反复“获取”。直到所有者为每个成功的“take”请求调用xSemaphoreGiveRecursive(),互斥量才会再次可用。
 * 例如,如果一个任务成功地“接受”了5次相同的互斥锁,那么这个互斥锁将不会对任何其他任务可用,直到它也恰好“给出”了5次互斥锁。
 *
 * 这种类型的信号量使用优先级继承机制,所以是任务“获取”一个信号量必须始终“返回”该信号量,一旦该信号量不再是必需的。
 *
 * 互斥类型信号量不能从中断服务例程中使用。
 *
 * Example usage:

 SemaphoreHandle_t xSemaphore;

 void vATask( void * pvParameters )
 {
    // 在调用xsemaphoreatemutex()之前,不能使用信号量。
    xSemaphore = xSemaphoreCreateRecursiveMutex();

    if( xSemaphore != NULL )
    {
        // 成功创建了信号量。现在可以使用信号量了。
    }
 }
 */
#if( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
    #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
#endif


/**创建静态递归互斥信号量
 * SemaphoreHandle_t xSemaphoreCreateRecursiveMutexStatic( StaticSemaphore_t *pxMutexBuffer )
 *
 * 创建一个新的递归互斥锁类型信号量实例,并返回一个句柄,通过该句柄可以引用新的递归互斥锁。
 *
 * 使用这个宏创建的互斥对象可以使用xSemaphoreTakeRecursive()和xSemaphoreGiveRecursive()宏访问。
 * 不能使用xSemaphoreTake()和xSemaphoreGive()宏。
 * 
 * 这种类型的信号量使用优先级继承机制,因此当不再需要信号量时,“接收take”该信号量的任务必须始终“返回give”该信号量。
 *
 * Example usage:

 SemaphoreHandle_t xSemaphore;
 StaticSemaphore_t xMutexBuffer;

 void vATask( void * pvParameters )
 {
    // 这里使用xsemaphoreaterecursivemutexstatic()创建递归互斥量。
    // xMutexBuffer的地址被传递到函数中,并保存互斥数据结构——因此不会尝试动态内存分配。
    xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xMutexBuffer );

    // 由于没有执行动态内存分配,xSemaphore不能为空,不需要检测。
 }
 */
#if( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
    #define xSemaphoreCreateRecursiveMutexStatic( pxStaticSemaphore ) xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxStaticSemaphore )
#endif /* configSUPPORT_STATIC_ALLOCATION */



/** 创建计数信号量。
 * SemaphoreHandle_t xSemaphoreCreateCounting( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount )
 *
 * 创建一个新的计数信号量实例,并返回一个句柄,通过该句柄可以引用新的计数信号量。
 *
 * 在许多使用场景中,使用直接到任务的通知代替计数信号量会更快、更节省内存
 *
 * 计数信号量通常用于两种情况:
 *
 * 1) 事件计数
 *
 * 在这个使用场景中,事件处理程序将在每次事件发生时“给出give”一个信号量(增加信号量计数值),
 * 而处理程序任务将在每次处理事件时“接受take”一个信号量(减少信号量计数值)。
 * 因此,count值是已发生的事件数与已处理的事件数之间的差值。在这种情况下,希望初始计数值为零。 
 *
 * 2) 资源管理
 *
 * 在这个使用场景中,count值指示可用资源的数量。要获得对资源的控制,任务必须首先获得一个信号量——减少信号量计数值。
 * 当计数值为零时,没有空闲资源。当任务使用资源完成时,它“返回give”信号量——增加信号量计数值。
 * 在这种情况下,希望初始计数值等于最大计数值,表示所有资源都是空闲的。
 *
 * @param uxMaxCount 可以达到的最大计数值。当信号量达到这个值时,它就不能再被“给定give”了。
 *
 * @param uxInitialCount 创建信号量时分配给它的计数值。
 *
 * Example usage:

 SemaphoreHandle_t xSemaphore;

 void vATask( void * pvParameters )
 {
    SemaphoreHandle_t xSemaphore = NULL;

    // 在调用xsemaphoatecounting()之前,不能使用信号量。
    // 信号量可以计数的最大值应该是10,分配给计数的初始值应该是0。
    xSemaphore = xSemaphoreCreateCounting( 10, 0 );

    if( xSemaphore != NULL )
    {
        // 成功创建了信号量。现在可以使用信号量了。
    }
 }
 */
#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
    #define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
#endif



/** 创建计数静态信号量。
 * SemaphoreHandle_t  xSemaphoreCreateCountingStatic( UBaseType_t uxMaxCount, UBaseType_t uxInitialCount, StaticSemaphore_t *pxSemaphoreBuffer )
 *
 * 创建一个新的计数信号量实例,并返回一个句柄,通过该句柄可以引用新的计数信号量。
 *
 * 在许多使用场景中,使用直接到任务的通知代替计数信号量会更快、更节省内存!

 * 计数信号量通常用于两种情况:
 *
 * 1) 事件计数
 *
 *    在这个使用场景中,事件处理程序将在每次事件发生时“给出”一个信号量(增加信号量计数值),而处理程序任务将在每次处理事件时“接受”一个信号量(减少信号量计数值)。
 *    因此,count值是已发生的事件数与已处理的事件数之间的差值。在这种情况下,希望初始计数值为零。
 *     
 * 2) 资源管理。
 *
 *    在这个使用场景中,count值指示可用资源的数量。要获得对资源的控制,任务必须首先获得一个信号量 ———— 减少信号量计数值。
 *    要获得对资源的控制,任务必须首先获得一个信号量——减少信号量计数值。
 *    当计数值为零时,没有空闲资源。当任务使用资源完成时,它“give”信号量 ———— 增加信号量计数值。
 *    在这种情况下,希望初始计数值等于最大计数值,表示所有资源都是空闲的。
 *
 * @param uxMaxCount 可以达到的最大计数值。当信号量达到这个值时,它就不能再被“给定”了。
 *
 * @param uxInitialCount 创建信号量时分配给它的计数值。
 *
 * @param pxSemaphoreBuffer 必须指向StaticSemaphore_t类型的变量,然后该变量将用于保存信号量的数据结构,从而消除动态分配内存的需要。
 *
 * @return 如果成功创建了计数信号量,则返回创建的计数信号量的句柄。如果pxSemaphoreBuffer为NULL,则返回NULL。
 *
 * Example usage:


 SemaphoreHandle_t xSemaphore;
 StaticSemaphore_t xSemaphoreBuffer;

 void vATask( void * pvParameters )
 {
    SemaphoreHandle_t xSemaphore = NULL;

    // 在创建信号量之前不能使用计数信号量。由xSemaphoreCreateCountingStatic()创建计数信号量。
    // 信号量可以计数的最大值为10,而分配给该计数的初始值为0。 传入xSemaphoreBuffer的地址,并将用于保存信号量结构,因此不会使用动态内存分配。
    xSemaphore = xSemaphoreCreateCounting( 10, 0, &xSemaphoreBuffer );

    // 没有尝试内存分配,因此xSemaphore不能为空,不需要检查它的值。
 }
 */
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
    #define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
#endif /* configSUPPORT_STATIC_ALLOCATION */



/**
 * 删除一个信号量。这个函数必须小心使用。例如,如果互斥对象由任务持有,则不要删除互斥对象类型信号量。
 *
 * @param xSemaphore 要删除的信号量的句柄。
 */
#define vSemaphoreDelete( xSemaphore ) vQueueDelete( ( QueueHandle_t ) ( xSemaphore ) )



/**
 * TaskHandle_t  xSemaphoreGetMutexHolder( SemaphoreHandle_t xMutex );
 *
 * 如果xMutex确实是一个互斥锁类型信号量,返回当前互斥锁持有者。
 * 如果xMutex不是互斥锁类型信号量,或者互斥锁可用(不是由任务持有),则返回NULL。
 *
 * 注意:这是确定调用任务是否是互斥锁持有者的好方法,但不是确定互斥锁持有者身份的好方法,因为持有者可能在函数退出和测试返回值之间发生变化。
 */
#define xSemaphoreGetMutexHolder( xSemaphore ) xQueueGetMutexHolder( ( xSemaphore ) )


/**
 * UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore ); //返回信号量当前的计数值
 *
 * 如果信号量是一个计数信号量,那么uxSemaphoreGetCount()返回它的当前计数值。
 * 如果信号量是二进制信号量,那么uxSemaphoreGetCount()在信号量可用时返回1,在信号量不可用时返回0。
 */
#define uxSemaphoreGetCount( xSemaphore ) uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )

#endif /* SEMAPHORE_H */