# 02 Crazyflie Source Preview

## Crazyflie源码分析

## 一、源代码结构

```
./              | Root, contains the Makefile
 + init         | 主文件目录,很简单 Contains the main.c
 + config       | 配置文件,包括系统任务配置文件,freertos配置文件, stm32配置文件 Configuration files
 + drivers      | 传感器底层访问驱动 Hardware driver layer
 |  + src       |  Drivers source code
 |  + interface |  Drivers header files. Interface to the HAL layer
 + hal          | 硬件抽象层  Hardware abstraction layer 主要包括sensors
 |  + src       | HAL source code
 |  + interface | HAL header files. Interface with the other parts of the program
 + modules      | 主要飞控代码 Firmware operating code and headers 角度计算 pid 等
 |  + src       | Firmware tasks source code and main.c
 |  + interface | Operating headers. Configure the firmware environment
 + utils        | CRC校验 IIR滤波器等 Utils code. Implement utility block like the console.
 |  + src       | Utils source code
 |  + interface | Utils header files. Interface with the other parts of the program
 + platform     | 平台信息 Platform specific files. Not really used yet
 + tools        | Misc. scripts for LD, OpenOCD, make, version control, ...
 |              | *** The two following folders contains the unmodified files ***
 + lib          | Libraries
 |  + FreeRTOS  | Source FreeRTOS folder. Cleaned up from the useless files
 |  + STM32...  | STM32外设库 Library folders of the ST STM32 peripheral libs
 |  + CMSIS     | ARM标准库 Core abstraction layer
```

## 二、运行任务

系统启动时主要运行的任务有,adcTask,crtpTxTask,crtpRxTask,eskylinkTask,infoTask,logTask,memTask,paramTask,pmTask,stabilizerTask,syslinkTask,systemTask,prvIdleTask,prvTimerTask和usblinkTask等任务.[分析链接](https://blog.csdn.net/xingqingly/article/details/49536923)

```
Adc_f103.c (drivers\src):  xTaskCreate(adcTask, (const signed char * const)"ADC",
Crtp.c (modules\src):  xTaskCreate(crtpTxTask, (const signed char * const)CRTP_TX_TASK_NAME,
Crtp.c (modules\src):  xTaskCreate(crtpRxTask, (const signed char * const)CRTP_RX_TASK_NAME,
Eskylink.c (hal\src):  xTaskCreate(eskylinkTask, (const signed char * const)ESKYLINK_TASK_NAME,
Info.c (modules\src):  xTaskCreate(infoTask, (const signed char * const)"Info",
Log.c (modules\src):  xTaskCreate(logTask, (const signed char * const)LOG_TASK_NAME,
Mem.c (modules\src):  xTaskCreate(memTask, (const signed char * const)MEM_TASK_NAME,
Nrf24link.c (hal\src):  xTaskCreate(nrf24linkTask, (const signed char * const)NRF24LINK_TASK_NAME,
Param.c (modules\src):    xTaskCreate(paramTask, (const signed char * const)PARAM_TASK_NAME,
Pidctrl.c (modules\src):  xTaskCreate(pidCrtlTask, (const signed char * const)"PIDCrtl",
Pm_f103.c (hal\src):  xTaskCreate(pmTask, (const signed char * const)PM_TASK_NAME,
Pm_f405.c (hal\src):  xTaskCreate(pmTask, (const signed char * const)PM_TASK_NAME,
Stabilizer.c (modules\src):  xTaskCreate(stabilizerTask, (const signed char * const)STABILIZER_TASK_NAME,
Syslink.c (hal\src):  if (xTaskCreate(syslinkTask, (const signed char * const)SYSLINK_TASK_NAME,
System.c (modules\src):  xTaskCreate(systemTask, (const signed char * const)SYSTEM_TASK_NAME,
Task.h (lib\freertos\include): * Type by which tasks are referenced.  For example, a call to xTaskCreate
Task.h (lib\freertos\include): portBASE_TYPE xTaskCreate(
Task.h (lib\freertos\include): * xTaskCreate() can only be used to create a task that has unrestricted
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include): * \defgroup xTaskCreate xTaskCreate
Task.h (lib\freertos\include):#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
Task.h (lib\freertos\include): * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include): * At least one task should be created via a call to xTaskCreate ()
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
Task.h (lib\freertos\include):     xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
Task.h (lib\freertos\include): * xTaskCreate() and xTaskCreateRestricted() macros.
Tasks.c (lib\freertos):        xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );
Tasks.c (lib\freertos):        xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );
Timers.c (lib\freertos):            xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
Timers.c (lib\freertos):            xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL);
Usblink.c (hal\src):  xTaskCreate(usblinkTask, (const signed char * const)USBLINK_TASK_NAME,
```

## 三、源码风格总结

Crazyflie项目中有很多巧妙的类型定义,可以很方便的解决问题,也可能是本人才疏学浅表示第一看看到这么用

### 1. 两种方式检索同一区域(union)

以下可以实现两种检索方式检索同一片内存区域,可以使用

```
 typedef union {
   struct {
         float x;
         float y;
         float z;
   };
   float axis[3];
 } Axis3f;
```

### 2. 使用枚举类型计数

以下枚举类型成员SensorImplementation\_COUNT,始终可以代表枚举类型中成员的个数.巧妙利用了枚举类型第一个成员默认为0的特点

```
typedef enum {  
  #ifdef SENSOR_INCLUDED_BMI088_BMP388
  SensorImplementation_bmi088_bmp388,
  #endif

  #ifdef SENSOR_INCLUDED_BMI088_SPI_BMP388
  SensorImplementation_bmi088_spi_bmp388,
  #endif

  #ifdef SENSOR_INCLUDED_MPU9250_LPS25H
  SensorImplementation_mpu9250_lps25h,
  #endif

  #ifdef SENSOR_INCLUDED_MPU6050_HMC5883L_MS5611
  SensorImplementation_mpu6050_HMC5883L_MS5611,
  #endif

  #ifdef SENSOR_INCLUDED_BOSCH
  SensorImplementation_bosch,
  #endif

  SensorImplementation_COUNT,
} SensorImplementation_t;
```

### 3. 紧凑的数据类型

```
struct cppmEmuPacket_s {
  struct {
      uint8_t numAuxChannels : 4;   // Set to 0 through MAX_AUX_RC_CHANNELS
      uint8_t reserved : 4;
  } hdr;
  uint16_t channelRoll;
  uint16_t channelPitch;
  uint16_t channelYaw;
  uint16_t channelThrust;
  uint16_t channelAux[MAX_AUX_RC_CHANNELS];
} __attribute__((packed));
```

**attribute** ((packed)) 的作用就是告诉编译器取消结构在编译过程中的优化对齐,按照实际占用字节数进行对齐,是GCC特有的语法.这个功能是跟操作系统没关系,跟编译器有关,gcc编译器不是紧凑模式的,我在windows下,用vc的编译器也不是紧凑的,用tc的编译器就是紧凑的.例如:

```
在TC下:struct my{ char ch; int a;} sizeof(int)=2;sizeof(my)=3;(紧凑模式)
在GCC下:struct my{ char ch; int a;} sizeof(int)=4;sizeof(my)=8;(非紧凑模式)
在GCC下:struct my{ char ch; int a;}__attrubte__ ((packed)) sizeof(int)=4;sizeof(my)=5
```

### 4. git工程中如何引用其他仓库

使用将其他仓库一起clone

```
git submodule init
git submodule update
```

### 5. 在makefile中添加宏定义

在Crazyflie的固件代码中,宏一般都定义在文件Makefile中.可以使用CFLAGS += -D的方式配置固件功能

```
# Flag that can be added to config.mk
CFLAGS += -DUSE_UART_CRTP        # Set CRTP link to UART
CFLAGS += -DUSE_ESKYLINK         # Set CRTP link to E-SKY receiver
CFLAGS += -DENABLE_UART          # To enable the uart
CFLAGS += -DDEBUG_PRINT_ON_UART  # Redirect the console output to the UART
```

```
CFLAGS += -DTOSH_DATA_LENGTH=114
```

相当于编译时

```
gcc -DTOSH_DATA_LENGTH=114 xx.c
```

相当于文件中添加

```
#define TOSH_DATA_LENGTH 114
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://libooogo.gitbook.io/esplane/research-on-crazyflie/07esplane-2.0-crazyfile-yuan-ma-yu-lan.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
