Code coverage collection for ArduPilot in real flight mode and software-in-the-loop (SITL) mode
Ardupilot compilation steps
1.Set the board subtype

./waf configure --board CUAVv5

2.Compile fixed wing
./waf plane

After compiling, compile_commands.json compilation database will be generated in build/CUAVv5/ directory.
Generate the bootable arduplane.apj firmware under build/CUAVv5/bin/.
Ardupilot instrumentation
1.Modify ZoaInstru.c
a.Change all the parameters to 1
b.change the parameter to 1 to open

c.Comment out the original code and modify it to
#define ZOA_IS_NORMAL(head)(((head)→type & 0×1f) == ZoaTypeNornmal)d. Add name to the structure
2. Change line 128 #define ZOA_CONST const to #define ZOA_CONST
3.Change the variable to 0


4.Put ZoaInstru.h in the shell/include directory
Put ZoaInstru.c in the ardupilot/ArduPlane directory
5.Create a project and associate
(default username: user, password: user)

a.A new project is being built here.

b.Click the red box to create a virtual project. Enter the name of the virtual project in the green box and the identifier of the virtual project in the blue box. Then click the purple box to save.

c.After adding, it will look like the following picture. Click "Add Real Project" on the right.

d.Add the real project name, select the project type, and click Confirm.

e.After successful creation, it will be displayed as shown in the following figure.

6.Instrumentation the compile_commands.json compilation database generated under the board subtype directory at compile time
a. Change the ip, etc. configuration at shlle/bin/Server.cfg

b.shlle/bin/Server.cfg modify configuration such as instrumentation black and white list

c.Create version./shell -c real project name Round name version name

d.Instrumentation./shell -p ../compile_commands.json

7. Copy the generated zoa_opt.c
After installing the shell/bin directory generate zoa_opt.c, this file will be put in the ardupilot/ArduPlane directory

Collect coverage data
To collect the coverage data, you need to write the coverage data to the ardupilot's file system, which is the SD card.
1.Modify ArduPlane/Plane.h
find the one_second_loop method definition, and add the write_to_sd_card(void) method definition in the figure in the next line

2. Modify ArduPlane/ Arduplane.cpp,
find the ahrs_update method implementation, and add the following code in the method
static int zoai = 0;
if (zoai == 0) {
hal.scheduler->register_timer_process(FUNCTOR_BIND_MEMBER(&Plane::write_to_sd_card, void));
zoai++;
}

3. modify ArduPlane/ arduplane.cpp
implement write_to_sd_card method, in AP_HAL_MAIN_CALLBACKS(&plane); Add the following before. This code will write the coverage of the entire file every 5 seconds. It's generated in the file system /APM/ZOA/ directory, called zoa_data, and it overwrites every time.
static int zoa_i = 0;
static int Zoafile;
static void save_to_file(struct __zoa_linker *linker) {
void *data;
int bytes;
struct zoa_data_info info;
info = zoa_get_data_info(linker);
data = info.datas[0];
bytes = info.bytes[0];
// Write data
AP::FS().write(Zoafile, data, bytes);
if (info.parts > 1) {
data = info.datas[1];
bytes = info.bytes[1];
AP::FS().write(Zoafile, data, bytes);
}
}
static void dump_all(void) {
char buf[256];
if (zoa_i < ZOA_FILE_MAX) {
// Open the file, only once
snprintf(buf, sizeof(buf), "/APM/ZOA/zoa_data");
//Zoafile = AP::FS().open(buf, O_RDWR | O_CREAT | O_APPEND);
Zoafile = AP::FS().open(buf, O_RDWR | O_CREAT);
if (Zoafile == -1) {
hal.console->println("Failed to open file.");
return;
}
// write data in a loop
while (zoa_i < ZOA_FILE_MAX) {
save_to_file(__zoa_list[zoa_i]);
zoa_i++;
}
// Write all the data before closing the file
AP::FS().close(Zoafile);
zoa_i = 0;
}
}
static int num = 1;
void Plane::write_to_sd_card(void) {
if (num % 5000 == 0) {
dump_all();
}
num++;
}

Compile the instrumented code
When compiling the instrumented code, since the build tool waf for this project has many strict compilation parameters configured, we need to comment out these configurations and also add configurations to include the ZoaInstru.h header file.
1. Modify ardupilot/wscript
Add the path where shell/include is located at line 519.

Line 628 also adds the path of shell/include

2. Modify the compilation parameters
Some configurations of -Werror need to be annotated; otherwise, it will be too strict and fail to compile. There are many changes. It is recommended to directly replace the modified file, or you can manually annotate based on the error messages after compilation.
ardupilot/Tools/ardupilotwaf/boards.py
ardupilot/Tools/ardupilotwaf/ar/dupilotwaf.py

3. Recompile again
Filter empty files uninstrumented because of macros
In some code of this project, there are some macros after preprocessing the condition is false, resulting in an empty file, but the instrumentation succeeds. But when you link zoa_opt.c, you can't link to the symbol. So you need to filter it out.
1.Single-thread instrumentation
Multi-threaded data is not allowed as it will be incomplete and disordered. Generate files_map.json in the shell/bin directory. This file records the correspondence between source code and link symbols.

2.Error resolution
After instrumentation, compiling will give an error when linking, for example, symbolic link __zoa_data_123 could not be found.At this time, the file with id 123 is found in files_map.json, and it is configured to the instrumentation blacklist. Generally, there will be multiple symbolic links that cannot be found. Restore all the files again and instrumentalize and compile them again.
SITL software simulates flight control

Software simulation can run the firmware on the computer without the board.
It is important to note that during the compilation of plane (fixed wing), our database is ardupilot instrumentation used to compile/build/CUAVv5/compile_commands json, and we use SITL software simulation, Instrumentation used to compile the database should be for ardupilot/build/sitl/compile_commands json
1.Compile the code and generate the compilation database.
../Tools/autotest/sim_vehicle.py -v ArduPlane --console --map


2.Use the current compiled database instrumentation after
ls .. /build/sitl/compile_commands.json
.. /build/sitl/compile_commands.json


3.Put the zoa_opt.c generated from the shell/bin directory after instrumentation into the project directory
cp .. /zoa_opt.c ./

4.Use software simulation again
.. /Tools/autotest/sim_vehicle.py -v ArduPlane --console --map

a. Enter the unlock command
arm throttle

b.Push the throttle above median and take off
rc 3 1700

c.Switch auto mode
mode auto

d.Set the simulation starting position and initial heading
Open locations.txt under the ardupilot\Tools\autotest folder and add a new location point in the second line. Add a location point named "NFCY_Home", latitude "66.66666", longitude "77.77777", elevation 20 meters, initial heading 30 degrees (latitude: north latitude is positive, south latitude is negative; Longitude: east longitude is positive, west longitude is negative);

Simulation script file, at the end of that line of command add a command: "-L your location name", in our example, after adding the script command is as follows:

Coverage data parsing
Earlier we added code to collect coverage, which is automatically written to the directory /APM/ZOA/zoa_data file every 5 seconds when the firmware starts.
1.Software emulation
a.The APM/ZOA directory needs to be prepared in the current directory of the simulation command
mkdir -p APM/ZOA

b.Simulation run
.. /Tools/autotest/sim_vehicle.py -v ArduPlane --console –map

After emulation, you can see that zoa_data has been generated.

2.Burn to the board for test use
Connect the board to the flight control and connect it to the sd card of the board via MAVFtp in the mission planner after creating the APM/ZOA directory. Connect the board again, and as you can see, zoa_data has been generated. Directly right click to download it locally.


Once you have the data, you need to send it to the server via zoa-server and zoa-sync.
3.Start zoa-server
specify the interface for the server to receive coverage data, and receive the data sent by zoa-sync
zoa-server.exe -dd_url="tcp://ip:15555" -mcdc_url="tcp://ip:15557" -cond_url "tcp://ip:15556" -enable_log -user_id 7

4.Start zoa-sync
zoa-sync.exe -cov_root ..\zoa_data
-cov_root specifies the directory where zoa_data is located
The following figure parses successfully

5.Wait for the zoa-server to finish sending

You can check the coverage in ttweb, ZoaInstru.h is configured with only statement block coverage before, so it is normal.

Code visualization
Points to note when using the code association tool TTSupport for code visualization in this project.
The file in the compiled data of the project is a relative path. If we directly instrumentate, it is very messy in ttweb, and it cannot be visualized after testing. We can use a script to change it to an absolute path.


For example my absolute path is /home/jianglei/ardupilot, I use the following script to process this file
sed -i 's#"file": ".. /.. #"file": "/home/jianglei/ardupilot#g' compile_commands.json
The compiled database after processing is as follows.

We again modify zoa_setting to filter out path prefixes

At this point it is very convenient to configure the visualization and it is also very simple to view on ttweb


Display of the basic functions of the platform
1.Forward and reverse traceability
Forward traceback, test cases are automatically associated with source code



Backward traceback, tracing the corresponding test case through the function

2.Regression testing
New version instrumentation testing, source code changes or additions, the system calculates the set of test cases to regression

3.Coverage View
a.Package coverage view

b.File coverage view

c.Function coverage view

d.Code visualization, block, condition, MC/DC coverage views


e.Function call graph

f.Function control flow chart
