Formatting and Generating API Descriptions
When you are documenting an API, there are some guidelines to follow, as demonstrated in Writing API Descriptions. Preparing such documentation could be tedious.
To simplify this process, ESP-Docs provides the run_doxygen.py extension, which generates API descriptions from header files during documentation build. This extension allows for automatic updates whenever code changes occur.
This document will cover the following topics:
Document API in Header Files
This section covers the formatting rules for API descriptions, so that the run_doxygen.py extension knows which descriptions should be extracted from header files.
In-Body Comments
In-body comments are used when documenting a macro
, a typedef
, and members of a struct
, enum
, etc. Such in-body comments start with /*!<
, and end with */
.
typedef struct {
type member_1; /*!< Explanation for structure member_1 */
type member_2; /*!< Explanation for structure member_2 */
type member_3; /*!< Explanation for structure member_3 */
} structure_name
Optionally, comment blocks can be used together with in-body comments when you provide overall descriptions for a struct
, enum
, etc.
/**
* @brief A brief explanation for this structure
*/
typedef struct {
type member_1; /*!< Explanation for structure member_1 */
type member_2; /*!< Explanation for structure member_2 */
type member_3; /*!< Explanation for structure member_3 */
} structure_name
You may skip repetitive macros, enumerations, or other code by enclosing them within /** @cond */
and /** @endcond */
, so that they will not show in the generated API descriptions:
/** @cond */
typedef struct esp_flash_t esp_flash_t;
/** @endcond */
Target-Specific Information
ESP-Docs introduces several functionalities to deal with target-specific contents (see Writing for Multiple Targets), but such functionalities are not supported for API descriptions generated from header files.
For target-specific information, it is preferable to use @note
to clarify the applicable targets.
Use @note
for a target-specific function:
/**
* @brief Enable RX PDM mode
* @note ESP32-C3: Not applicable, because it doesn't support RX PDM mode.
*
* @param hw Peripheral I2S hardware instance address
* @param pdm_enable Set true to RX enable PDM mode (ignored)
*/
static inline void i2s_ll_rx_enable_pdm(i2s_dev_t *hw, bool pdm_enable)
Use @note
for a target-specific struct
:
/**
* @brief ADC digital controller (DMA mode) output data format.
* Used to analyze the acquired ADC (DMA) data.
* @note ESP32: Only `type1` is valid. ADC2 does not support DMA mode.
*/
typedef struct {
union {
struct {
uint16_t data: 12; /*!<ADC real output data info. Resolution: 12 bit */
uint16_t channel: 4; /*!<ADC channel index info */
} type1; /*!<ADC type1 */
struct {
uint16_t data: 11; /*!<ADC real output data info Resolution: 11 bit. */
uint16_t channel: 4; /*!<ADC channel index info. For ESP32-S2:
If (channel < ADC_CHANNEL_MAX), The data is valid.
If (channel > ADC_CHANNEL_MAX), The data is invalid. */
uint16_t unit: 1; /*!<ADC unit index info. 0: ADC1; 1: ADC2. */
} type2; /*!<When the configured output format is 11 bit.*/
uint16_t val; /*!<Raw data value */
};
} adc_digi_output_data_t;
Alternatively, you can use if statements (#if
and #endif
directives in C language) together with macros defined in *_caps.h
header files as shown in the following examples.
Note
Please note that some developers tend to read header files directly instead of API documentattion. If statements would make header files hard to read, so they are less recommended.
Use an if statement to mark a target-specific function:
#if SOC_I2C_SUPPORT_SLAVE
/**
* @brief Write bytes to internal ringbuffer of the I2C slave data. When the TX fifo empty, the ISR will
* fill the hardware FIFO with the internal ringbuffer's data.
* @note This function shall only be called in I2C slave mode.
*
* @param i2c_num I2C port number
* @param data Bytes to write into internal buffer
* @param size Size, in bytes, of `data` buffer
* @param ticks_to_wait Maximum ticks to wait
*
* @return
* - ESP_FAIL (-1): Parameter error
* - Other (>=0): The number of data bytes pushed to the I2C slave buffer
*/
int i2c_slave_write_buffer(i2c_port_t i2c_num, const uint8_t *data, int size, TickType_t ticks_to_wait);
#endif // SOC_I2C_SUPPORT_SLAVE
Use an if statement to mark a target-specific enum
:
/**
* @brief I2C port number, can be I2C_NUM_0 ~ (I2C_NUM_MAX-1)
*/
typedef enum {
I2C_NUM_0 = 0, /*!< I2C port 0 */
#if SOC_I2C_NUM >= 2
I2C_NUM_1, /*!< I2C port 1 */
#endif
I2C_NUM_MAX, /*!< I2C port max */
} i2c_port_t;
Style
When preparing the API descriptions, follow the style below for consistency:
The maximum line length is 120 characters for better code readability, as described in Espressif IoT Development Framework Style Guide
If descriptions in combination with code are more than 120 characters, manually break lines, or consider if the descriptions better fit in the main text (namely the
.rst
files)Capitalize the first word of every sentence segment or sentence
End all complete sentences with periods
.
If a sentence fragment is at the end of a line, or the line contains only one sentence fragment, then omit the ending periods
.
An ending period
.
will be added automatically to each@brief
(see line 3 in the updated example and the its rendered result).Use bullet points if there are 2 or more returned values
Use
:
between a returned value and its meaningBetween parameters and parameter meanings, do not add any punctuation marks such as
-
and:
The example below shows how to follow above style after >>>
:
1 /**
2 *
3 * @brief This function is called to send wifi connection report >>> Should add a ending period "." for complete sentences
4 * @param opmode : wifi opmode >>> Should delete the colon ":" between parameter's name and perameters' meaning
5 * @param sta_conn_state : station is already in connection or not >>> Should be capitalized
6 * @param softap_conn_num : softap connection number
7 * @param extra_info : extra information, such as sta_ssid, softap_ssid and etc.
8 *
9 * @return ESP_OK - success, other - failed >>> Values should be listed using bullet points, and "-" should be changed to ":"
10 *
11 */
12 esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_t opmode, esp_blufi_sta_conn_state_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *extra_info);
Above examples can be updated as follows in line with the rules (note that the returned error codes and their descriptions in line 10 can be more specific):
1 /**
2 *
3 * @brief Send Wi-Fi connection report
4 * @param opmode Wi-Fi operation mode
5 * @param sta_conn_state Whether station is connected or not
6 * @param softap_conn_num SoftAP connection number
7 * @param extra_info Extra information, such as sta_ssid, softap_ssid and etc.
8 *
9 * @return
10 * - ESP_OK: Done
11 * - Other error code: Failed
12 *
13 */
14 esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_t opmode, esp_blufi_sta_conn_state_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *extra_info);
Generate and Include API Descriptions
Doxyfile
is the must-have Doxygen configuration file for automatic API generation. All header files used to generate API should be included in Doxyfile
. For example, please refer to the Doxyfile of ESP-IDF.
Note
Target-specific header files may be placed in a separate Doxyfile
. For example, Doxyfile_esp32 is provided to generate ESP32-specific API descriptions in ESP-IDF.
ESP-Docs integrates API generation into the process of building documentation. To be specific, when you run the command to build documentation (see Building Documentation Locally), run_doxygen.py generates .inc
files from input header files defined in Doxyfile
according to configuration, and places the ouput files in _build/$(language)/$(target)/inc
directory.
To include the generated .inc
files into .rst
files, use the include-build-file::
directive defined in include_build_file.py .
API Reference
-------------
.. include-build-file:: inc/i2c.inc
Linking to Functions, Enumerations, etc
To link to a function, enumeration, and other structure types described in API descriptions, please refer to Linking to Classes, Functions, Enumerations, etc.
Example
For reference, you may navigate to the doxygen folder, and check the header files stored in the src/api
subfolders.
To see the API descriptions in HTML, please run build_example.sh
.
Comment Blocks
Comment blocks are used when documenting
functions
. Such comment blocks start with/**
, and end with*/
. Other lines within comment blocks should be marked with*
at the beginning:@brief
,@param
, and@return
form the basic structure for API descriptions.@param
and@return
can be skipped if a function does not have parameters or return any response.If the function might return different responses, use a bullet list to document the responses under
@return
.Comment blocks have some addtional features, which can make the formatting of API descriptions fancier:
Use [in], [out], [in, out] to document the direction of parameters:
Add notes, warnings, or attentions after
@note
,@warning
, or@attention
respectively:Add code snippets enclosed by
@code{c}
and@endcode
:Group similar functions by enclosing them with
/**@{*/
and/**@}*/
:Use Markdown Syntax: