| Supported Targets | ESP32 |
| ----------------- | ----- |

# Blink Example With Coverage Info (Gcov)

(See the README.md file in the upper level 'examples' directory for more information about examples.)

The following example demonstrates how to compile an ESP-IDF project to generate code coverage data, and how generate a code coverage report using Gcov or Lcov. Refer to the [Gcov Guide](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/app_trace.html#gcov-source-code-coverage) for more details on the code coverage features supported in ESP-IDF.

This example implements a simple blink application but with code coverage enabled. The example will demonstrate the following features:
* How to compile a project with coverage info enabled.
* Various methods of dumping code coverage data (e.g. Instant Run-Time Dump and Hard-coded Dump).
* How to generate a code coverage report.

## How to use example

### Hardware Required

To run this example, you need an ESP32 dev board connected to a JTAG adapter, which can come in the following forms:

* [ESP-WROVER-KIT](https://docs.espressif.com/projects/esp-idf/en/latest/hw-reference/modules-and-boards.html#esp-wrover-kit-v4-1) which integrates an on-board JTAG adapter. Ensure that the [required jumpers to enable JTAG are connected](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/get-started-wrover-kit.html#setup-options) on the WROVER-KIT.
* ESP32 core board (e.g. ESP32-DevKitC) can also work as long as you connect it to an external JTAG adapter (e.g. FT2232H, J-LINK).

This example will assume that that an ESP-WROVER-KIT is used.

1. Connect the JTAG interface to ESP32 board, and power up both the JTAG and ESP32. For details about how to set up JTAG interface, please see [JTAG Debugging](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html).

2. After connecting JTAG interface, you need to [Run OpenOCD](https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/jtag-debugging/index.html#run-openocd).

3. Open a separate terminal window and run telnet by entering the command below. The telnet terminal window is used to feed commands to OpenOCD:

```bash
telnet localhost 4444
```

### Configure the project

```
idf.py menuconfig
```

The example will enable the following options by default:

* Enable the Application Tracing Module under `Component config -> Application Level Tracing -> Data Destination` by choosing `Trace memory`.
* Enable GCOV to host interface under `Component config -> Application Level Tracing -> GCOV to Host Enable`.
* Enable OpenOCD Debug Stubs under `Component config -> ESP32-specific -> OpenOCD debug stubs`

### Build, Flash, and Run

Build the project and flash it to the board, then run monitor tool to view serial output:

```
idf.py -p PORT flash monitor
```

(Replace PORT with the name of the serial port to use.)

(To exit the serial monitor, type ``Ctrl-]``.)

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

## Example Output

### 1. Hard-coded Dump

The example will initially execute two hard-coded dumps. Therefore, when the application outputs `Ready to dump GCOV data...`, users should execute the `esp gcov dump` OpenOCD command. The example should output the following:

```
blink_dummy_func: Counter = 0
some_dummy_func: Counter = 0
Ready to dump GCOV data...
GCOV data have been dumped.
blink_dummy_func: Counter = 1
some_dummy_func: Counter = 2
Ready to dump GCOV data...
GCOV data have been dumped.
```

### 2. Instant Run-Time Dump

After the two hard-coded dumps, the example will continue looping through it's main blink function. Users can call `esp gcov` OpenOCD command to trigger an instant run-time dump. The output should resemble the following:

```
blink_dummy_func: Counter = 2
some_dummy_func: Counter = 4
blink_dummy_func: Counter = 3
some_dummy_func: Counter = 6
blink_dummy_func: Counter = 4
some_dummy_func: Counter = 8
blink_dummy_func: Counter = 5
some_dummy_func: Counter = 10
blink_dummy_func: Counter = 6
some_dummy_func: Counter = 12
blink_dummy_func: Counter = 7
some_dummy_func: Counter = 14
blink_dummy_func: Counter = 8
some_dummy_func: Counter = 16
blink_dummy_func: Counter = 9
some_dummy_func: Counter = 18
blink_dummy_func: Counter = 10
some_dummy_func: Counter = 20
...
```

### Generating Gcovr Report

After dumping one or more times, a coverage report can be generated by calling `cmake --build build/ --target gcovr-report`. This should result in an HTML code coverage report being generated in the build directory.

To clean Gcov and report related data from the build directory, call `cmake --build build/ --target cov-data-clean`

The following log should be output when generating the coverage report:

```
[1/2] Generating coverage report in: /home/user/esp/esp-idf/examples/system/gcov/build/coverage_report
Using gcov: xtensa-esp32-elf-gcov
[2/2] cd /home/user/esp/esp-idf/examples/system/gcov/build && gcovr -r /home/user/esp/esp-idf/examples/system/gcov...a-esp32-elf-gcov -s --html-details /home/user/esp/esp-idf/examples/system/gcov/build/coverage_report/html/index.htm
lines: 100.0% (27 out of 27)
branches: 100.0% (2 out of 2)
```

## Troubleshooting

### OpenOCD Out of Sync

If the following log is output when issuing an OpenOCD command via telnet, it could indicate that OpenOCD and the ESP32 are out of sync. This occurs when the ESP32 is externally reset whilst connected to OpenOCD (e.g., by pressing the EN button).

```
Open On-Chip Debugger
> esp gcov dump
Target halted. PRO_CPU: PC=0x4008AFF4 (active)    APP_CPU: PC=0x400E396E
Total trace memory: 16384 bytes
Connect targets...
Target halted. PRO_CPU: PC=0x400D5D74 (active)    APP_CPU: PC=0x400E396E
timed out while waiting for target halted / 1 - 2
Failed to wait halt on bp target (-4)!
Failed to halt targets (-4)!
Failed to connect to targets (-4)!
```

This issue can be resolved in the following ways:
* Reset the board by issuing the `reset` command via telnet
* Restart OpenOCD

### gcovr not found

gcovr can be installed from the package database of your operating system or directly as a Python package, e.g:

```
    python -m pip install gcovr
```
