FreeRTOS源码解析——第二章 编程规范

2023-05-16

FreeRTOS源码解析

第一章 FreeRTOS 整体架构
第二章 FreeRTOS 编程规范
第三章 FreeRTOS 内存管理
第三章 FreeRTOS 内存管理
第四章 FreeRTOS 任务管理
第五章 FreeRTOS 消息队列
第六章 FreeRTOS 软件定时器
第七章 FreeRTOS 信号量
第八章 FreeRTOS 互斥量
第九章 FreeRTOS 任务通知
第十章 FreeRTOS 事件组


FreeRTOS源码解析——第二章 编程规范

  • FreeRTOS源码解析
  • 前言
  • 一、编码标准
  • 二、命名规则
    • 2.1 宏
      • 2.1.1 规则
      • 2.1.2 实例
    • 2.2、变量
      • 2.2.1 stdint 命名的变量
      • 2.2.2 FreeRTOS 定义的数据类型
      • 2.2.3 指针类型
    • 2.3、函数
      • 2.3.1 static 函数
      • 2.3.2 全局函数
  • 三、数据类型
  • 四、注释和风格
  • 总结


前言

本章主要介绍FreeRTOS的命名、注释、数据结构等编码规范。方便后续的源码阅读。


一、编码标准

FreeRTOS的核心代码遵从MISRA-C(汽车产业软件可靠性协会)编码标准。如果出现有不满足标准的会在代码中显示注释出来。可以在代码中全局搜索"MISRA exception"找到不满足MISRA-C标准的编码。在FreeRTOSV10.4.6中一共有27处不满足,不同类型的如下:

/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
 * because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
 * for the header files above, but not in this file, in order to generate the
 * correct privileged Vs unprivileged linkage and placement. */
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e9021 !e961 !e750. */
if( ( ( TickType_t ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks ) /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); /*lint !e923 !e9033 !e9078 MISRA exception.  Avoiding casts between pointers and integers is not practical.  Size differences accounted for using portPOINTER_SIZE_TYPE type.  Checked by assert(). */
if( pxQueue->pcWriteTo >= pxQueue->u.xQueue.pcTail )    /*lint !e946 MISRA exception justified as comparison of pointers is the cleanest solution. */
pxQueue->pcWriteTo += pxQueue->uxItemSize;   /*lint !e9016 Pointer arithmetic on char types ok, especially in this use case where it is the clearest way of conveying intent. */
( void ) memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 !e9087 MISRA exception as the casts are only redundant for some ports.  Also previous logic ensures a null pointer can only be passed to memcpy() when the count is 0.  Cast to void required by function signature and safe as no alignment requirement and copy length specified in bytes. */

二、命名规则

2.1 宏

2.1.1 规则

  • 前缀:小写,作为宏的起始部分(所在文件的简写)
  • 其余部分为大写,两个单词之间用下划线隔开(第一个大写和前缀之间没有下划线间隔)

2.1.2 实例

  • portmacro.h
    #define portCHAR          char
    #define portFLOAT         float
    #define portDOUBLE        double
    #define portLONG          long
    #define portSHORT         short
    #define portSTACK_TYPE    uint32_t
    #define portBASE_TYPE     long
  • FreeRTOSConfig.h
#define configUSE_PREEMPTION			1
#define configCPU_CLOCK_HZ				( 100000000 )
  • task.c task.h
#define tskDEFAULT_INDEX_TO_NOTIFY     ( 0 )
#define tskRUNNING_CHAR      ( 'X' )
  • queue.c queue.h
#define queueSEND_TO_BACK                     ( ( BaseType_t ) 0 )
#define queueSEND_TO_FRONT                    ( ( BaseType_t ) 1 )
#define queueOVERWRITE                        ( ( BaseType_t ) 2 )

2.2、变量

命名规则:位宽前缀Name1Name2…Namex

2.2.1 stdint 命名的变量

  • 8bit(char)无符号:uint8_t 前缀 ‘uc’
    8bit(char)有符号:int8_t 前缀 ‘c’
uint8_t ucQueueType;
int8_t  cRxLock;
char cStatus;
  • 16bit(short)无符号:uint16_t 前缀 ‘us’
    16bit(short)有符号:int16_t 前缀 ‘s’
FreeRTOS中没有直接用 uint16_tint16_t 命名的变量
  • 32bit(long)无符号:uint32_t 前缀 ‘ul’
    32bit(long)有符号:int32_t 前缀 ‘l’
uint32_t ulStackDepth
int32_t  lArrayIndex;

2.2.2 FreeRTOS 定义的数据类型

FreeRTOS 的自定义的数据类型如下:

/* integer data type */
typedef portSTACK_TYPE   StackType_t;
typedef long             BaseType_t;
typedef unsigned long    UBaseType_t;
typedef uint32_t     TickType_t;  /* 32bit hardware*/

/* defined by freertos */
typedef struct tskTaskControlBlock * TaskHandle_t;
typedef struct QueueDefinition   * QueueHandle_t;
typedef xTIMER Timer_t;
typedef struct EventGroupDef_t   * EventGroupHandle_t

FreeRTOS自定义的数据类型只有两种前缀,如下:

  • 整型无符号前缀 ‘ux’
  • 整型有符号和FreeRTOS自定义的数据类型前缀 ‘x’
/* integer data type */
UBaseType_t uxTimerNumber;
BaseType_t xListWasEmpty;
StackType_t xStack[ STACK_SIZE ];
TickType_t xNextExpireTime;

/* defined by freertos */
TaskHandle_t xTimerTaskHandle = NULL;
QueueHandle_t xTimerQueue = NULL;
Timer_t xNewTimer;
EventGroupHandle_t xEventGroup = NULL;

2.2.3 指针类型

在2.2.1和2.2.2的数据类型的命名前面增加 ‘p’

uint8_t * pucStackByte;
int8_t * pcOriginalReadPosition;
uint32_t * pulNotificationValue;

StackType_t * pxTopOfStack;
BaseType_t * pxHigherPriorityTaskWoken
UBaseType_t *puxVariableToIncrement;
TickType_t * const pxTicksToWait;

TaskHandle_t *pxCreatedTask;
Queue_t * pxNewQueue ;
Timer_t * const pxTimer;
EventGroup_t * pxEventBits;

2.3、函数

2.3.1 static 函数

  • 只在当前文件有效的, 被 static 修饰: 增加前缀 “prv” ,private的意思 。不区分有无返回值、返回值是否为指针等,统一固定前缀 “prv”。
  • 规则: prvName1Name2…Namex
  • 实例如下:
/*  task.c */
static void prvDeleteTCB( TCB_t * pxTCB )
/*  queue.c */
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void * pvItemToQueue, const BaseType_t xPosition )

2.3.2 全局函数

  • 有返回值前缀为 ‘x’ 或’ux’,无返回值前缀为 ‘v’
  • 返回值为指针,增加前缀 ‘p’
  • 前缀后面紧跟着所在文件名的缩写
  • 实例如下:
/* task.c */
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
/* queue.c */
BaseType_t xQueueIsQueueEmptyFromISR( const QueueHandle_t xQueue )
/* timer.c */
void vTimerSetTimerID( TimerHandle_t xTimer, void * pvNewID )
/* porttable.h */
void * pvPortMalloc( size_t xSize )

三、数据类型

见 2.2节,变量的命令。主要就是三种数据类型

  • stdint.h 命名的整型
  • FreeRTOS 命名的整型
  • FreeRTOS自定义的 链表、句柄等服务于各个模块的结构体

四、注释和风格

  • 注释:只用 /* */ 进行注释
  • 头文件中会给出函数的说明和例程,方便查阅和使用
  • 源文件中关键处也会有对应的注释,辅助理解
  • 缩进:4个空格
  • 关键字 for、if、while等后面没有空格
  • 实例如下:
/**************** timer.h **************/
/**
 * BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer );
 *
 * Queries a timer to see if it is active or dormant.
 *
 * A timer will be dormant if:
 *     1) It has been created but not started, or
 *     2) It is an expired one-shot timer that has not been restarted.
 *
 * Timers are created in the dormant state.  The xTimerStart(), xTimerReset(),
 * xTimerStartFromISR(), xTimerResetFromISR(), xTimerChangePeriod() and
 * xTimerChangePeriodFromISR() API functions can all be used to transition a timer into the
 * active state.
 *
 * @param xTimer The timer being queried.
 *
 * @return pdFALSE will be returned if the timer is dormant.  A value other than
 * pdFALSE will be returned if the timer is active.
 *
 * Example usage:
 * @verbatim
 * // This function assumes xTimer has already been created.
 * void vAFunction( TimerHandle_t xTimer )
 * {
 *     if( xTimerIsTimerActive( xTimer ) != pdFALSE ) // or more simply and equivalently "if( xTimerIsTimerActive( xTimer ) )"
 *     {
 *         // xTimer is active, do something.
 *     }
 *     else
 *     {
 *         // xTimer is not active, do something else.
 *     }
 * }
 * @endverbatim
 */
BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;

/**************** timer.c**************/
    BaseType_t xTimerIsTimerActive( TimerHandle_t xTimer )
    {
        BaseType_t xReturn;
        Timer_t * pxTimer = xTimer;

        configASSERT( xTimer );

        /* Is the timer in the list of active timers? */
        taskENTER_CRITICAL();
        {
            if( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) == 0 )
            {
                xReturn = pdFALSE;
            }
            else
            {
                xReturn = pdTRUE;
            }
        }
        taskEXIT_CRITICAL();

        return xReturn;
    } /*lint !e818 Can't be pointer to const due to the typedef. */

总结

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS源码解析——第二章 编程规范 的相关文章

随机推荐