Skip to content

Commit f5c3189

Browse files
committed
fix(esp_commands): Incorporate review comments
1 parent a8199e1 commit f5c3189

File tree

5 files changed

+186
-171
lines changed

5 files changed

+186
-171
lines changed

esp_commands/.build-test-rules.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
esp_commands/test_apps:
22
enable:
3-
- if: (IDF_TARGET == "linux") and (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 3)
4-
reason: "Test the main logic of the component (not target dependent)"
5-
- if: IDF_TARGET == "esp32"
6-
reason: "Test the placement of statically registered commands in dedicated flash section"
3+
- if: (IDF_TARGET in ["esp32", "linux"]) and (IDF_VERSION_MAJOR == 5 and IDF_VERSION_MINOR >= 3)

esp_commands/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ typedef struct esp_command {
6060
Use the `ESP_COMMAND_REGISTER` macro to register a command at compile time:
6161

6262
```c
63-
static int my_cmd(void *ctx, int argc, char **argv) {
63+
static int my_cmd(void *context, esp_commands_exec_arg_t *cmd_arg, int argc, char **argv) {
6464
printf("Hello from my_cmd!\n");
6565
return 0;
6666
}
6767

6868
ESP_COMMAND_REGISTER(my_cmd, tools, "Prints hello", my_cmd, NULL, NULL, NULL);
6969
```
7070
71-
This places the command into the `.esp_commands` section.
71+
This places the command into the `.esp_commands` section in flash.
7272
7373
### Dynamic Registration
7474

esp_commands/include/esp_commands.h

Lines changed: 1 addition & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -10,170 +10,10 @@ extern "C" {
1010
#endif
1111

1212
#include <stdbool.h>
13+
#include "esp_commands_utils.h"
1314
#include "esp_heap_caps.h"
1415
#include "esp_err.h"
1516

16-
#define _STRINGIFY(name) #name
17-
18-
/**
19-
* @brief Function pointer type for writing bytes.
20-
*
21-
* @param fd File descriptor.
22-
* @param buf Buffer containing bytes to write.
23-
* @param count Number of bytes to write.
24-
* @return Number of bytes written, or -1 on error.
25-
*/
26-
typedef ssize_t (*esp_commands_write_t)(int fd, const void *buf, size_t count);
27-
28-
/**
29-
* @brief Structure containing dynamic argument necessary for the\
30-
* command callback to execute properly
31-
*/
32-
typedef struct esp_commands_exec_arg {
33-
int out_fd; /*!< file descriptor that the command function has to use to output data */
34-
esp_commands_write_t write_func; /*!< write function the command function has to use to output datga */
35-
void *dynamic_ctx; /*!< dynamic context passed to the command function */
36-
} esp_commands_exec_arg_t;
37-
38-
/**
39-
* @brief Console command main function type with user context
40-
*
41-
* This function type is used to implement a console command.
42-
*
43-
* @param context User-defined context passed at invocation
44-
* @param cmd_arg Structure containing dynamic arguments necessary for the command
45-
* @param argc Number of arguments
46-
* @param argv Array of argc entries, each pointing to a null-terminated string argument
47-
* @return Return code of the console command; 0 indicates success
48-
*/
49-
typedef int (*esp_command_func_t)(void *context, esp_commands_exec_arg_t *cmd_arg, int argc, char **argv);
50-
51-
/**
52-
* @brief Callback to generate a command hint
53-
*
54-
* This function is called to retrieve a short hint for a command,
55-
* typically used for auto-completion or UI help.
56-
*
57-
* @param context Context registered when the command was registered
58-
* @return Persistent string containing the generated hint
59-
*/
60-
typedef const char *(*esp_command_hint_t)(void *context);
61-
62-
/**
63-
* @brief Callback to generate a command glossary entry
64-
*
65-
* This function is called to retrieve detailed description or glossary
66-
* information for a command.
67-
*
68-
* @param context Context registered when the command was registered
69-
* @return Persistent string containing the generated glossary
70-
*/
71-
typedef const char *(*esp_command_glossary_t)(void *context);
72-
73-
/**
74-
* @brief Structure describing a console command
75-
*
76-
* @note The `group` field allows categorizing commands into groups,
77-
* which can simplify filtering or listing commands.
78-
*/
79-
typedef struct esp_command {
80-
const char *name; /*!< Name of the command */
81-
const char *group; /*!< Command group to which this command belongs */
82-
const char *help; /*!< Short help text for the command */
83-
esp_command_func_t func; /*!< Function implementing the command */
84-
void *func_ctx; /*!< User-defined context for the command function */
85-
esp_command_hint_t hint_cb; /*!< Callback returning the hint for the command */
86-
esp_command_glossary_t glossary_cb; /*!< Callback returning the glossary for the command */
87-
} esp_command_t;
88-
89-
/**
90-
* @brief Macro to define a forced inline accessor for a string field of esp_command_t
91-
*
92-
* @param NAME Field name of the esp_command_t structure
93-
*/
94-
#define DEFINE_FIELD_ACCESSOR(NAME) \
95-
static inline __attribute__((always_inline)) \
96-
const char *get_##NAME(const esp_command_t *cmd) { \
97-
if (!cmd) { \
98-
return NULL; \
99-
} \
100-
return cmd->NAME; \
101-
}
102-
103-
/**
104-
* @brief Macro expanding to
105-
* static inline __attribute__((always_inline)) const char *get_name(esp_command_t *cmd) {
106-
* if (!cmd) {
107-
* return NULL;
108-
* }
109-
* return cmd->name;
110-
* }
111-
*/
112-
DEFINE_FIELD_ACCESSOR(name)
113-
114-
/**
115-
* @brief Macro expanding to
116-
* static inline __attribute__((always_inline)) const char *get_group(esp_command_t *cmd) {
117-
* if (!cmd) {
118-
* return NULL;
119-
* }
120-
* return cmd->group;
121-
* }
122-
*/
123-
DEFINE_FIELD_ACCESSOR(group)
124-
125-
/**
126-
* @brief Macro expanding to
127-
* static inline __attribute__((always_inline)) const char *get_help(esp_command_t *cmd) {
128-
* if (!cmd) {
129-
* return NULL;
130-
* }
131-
* return cmd->help;
132-
* }
133-
*/
134-
DEFINE_FIELD_ACCESSOR(help)
135-
136-
/**
137-
* @brief Macro to create the accessor function name for a field of esp_command_t
138-
*
139-
* @param NAME Field name of esp_command_t
140-
*/
141-
#define FIELD_ACCESSOR(NAME) get_##NAME
142-
143-
/**
144-
* @brief Configuration parameters for esp_commands_manager initialization
145-
*/
146-
typedef struct esp_commands_config {
147-
uint32_t heap_caps_used; /*!< Set of heap capabilities to be used to perform internal allocations */
148-
size_t max_cmdline_length; /*!< Maximum length of the command line buffer, in bytes */
149-
size_t max_cmdline_args; /*!< Maximum number of command line arguments to parse */
150-
int hint_color; /*!< ANSI color code used for hint text */
151-
bool hint_bold; /*!< If true, display hint text in bold */
152-
} esp_commands_config_t;
153-
154-
/**
155-
* @brief Callback for a completed command name
156-
*
157-
* This callback is called when a command is successfully completed.
158-
*
159-
* @param cb_ctx Opaque pointer pointing at the context passed to the callback
160-
* @param completed_cmd_name Completed command name
161-
*/
162-
typedef void (*esp_command_get_completion_t)(void *cb_ctx, const char *completed_cmd_name);
163-
164-
/**
165-
* @brief Callback to retrieve a string field of esp_command_t
166-
*
167-
* @param cmd Command object
168-
* @return Value of the requested string field
169-
*/
170-
typedef const char *(*esp_commands_get_field_t)(const esp_command_t *cmd);
171-
172-
/**
173-
* @brief Opaque handle to a set of commands
174-
*/
175-
typedef struct esp_command_sets *esp_command_set_handle_t;
176-
17717
/**
17818
* @brief Update the component configuration
17919
*
@@ -187,9 +27,6 @@ esp_err_t esp_commands_update_config(const esp_commands_config_t *config);
18727
* @brief macro registering a command and placing it in a specific section of flash.rodata
18828
* @note see the linker.lf file for more information concerning the section characteristics
18929
*/
190-
#define _ESP_REPL_STRINGIFY(x) #x
191-
#define ESP_REPL_STRINGIFY(x) _ESP_REPL_STRINGIFY(x)
192-
19330
#define _ESP_COMMAND_REGISTER(cmd_name, cmd_group, cmd_help, cmd_func, cmd_func_ctx, cmd_hint_cb, cmd_glossary_cb) \
19431
static_assert((cmd_func) != NULL); \
19532
static const esp_command_t cmd_name __attribute__((used, section(".esp_commands" "." _ESP_REPL_STRINGIFY(cmd_name)), aligned(4))) = { \
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#pragma once
7+
8+
#ifdef __cplusplus
9+
extern "C" {
10+
#endif
11+
12+
#include <stdbool.h>
13+
#include <stdint.h>
14+
15+
#define _ESP_REPL_STRINGIFY(x) #x
16+
#define ESP_REPL_STRINGIFY(x) _ESP_REPL_STRINGIFY(x)
17+
18+
/**
19+
* @brief Function pointer type for writing bytes.
20+
*
21+
* @param fd File descriptor.
22+
* @param buf Buffer containing bytes to write.
23+
* @param count Number of bytes to write.
24+
* @return Number of bytes written, or -1 on error.
25+
*/
26+
typedef ssize_t (*esp_commands_write_t)(int fd, const void *buf, size_t count);
27+
28+
/**
29+
* @brief Structure containing dynamic argument necessary for the\
30+
* command callback to execute properly
31+
*/
32+
typedef struct esp_commands_exec_arg {
33+
int out_fd; /*!< file descriptor that the command function has to use to print data in the environment it was called from */
34+
esp_commands_write_t write_func; /*!< write function the command function has to use to output datga */
35+
void *dynamic_ctx; /*!< dynamic context passed to the command function */
36+
} esp_commands_exec_arg_t;
37+
38+
/**
39+
* @brief Console command main function type with user context
40+
*
41+
* This function type is used to implement a console command.
42+
*
43+
* @param context User-defined context passed at invocation
44+
* @param cmd_arg Structure containing dynamic arguments necessary for the command
45+
* @param argc Number of arguments
46+
* @param argv Array of argc entries, each pointing to a null-terminated string argument
47+
* @return Return code of the console command; 0 indicates success
48+
*/
49+
typedef int (*esp_command_func_t)(void *context, esp_commands_exec_arg_t *cmd_arg, int argc, char **argv);
50+
51+
/**
52+
* @brief Callback to generate a command hint
53+
*
54+
* This function is called to retrieve a short hint for a command,
55+
* typically used for auto-completion or UI help.
56+
*
57+
* @param context Context registered when the command was registered
58+
* @return Persistent string containing the generated hint
59+
*/
60+
typedef const char *(*esp_command_hint_t)(void *context);
61+
62+
/**
63+
* @brief Callback to generate a command glossary entry
64+
*
65+
* This function is called to retrieve detailed description or glossary
66+
* information for a command.
67+
*
68+
* @param context Context registered when the command was registered
69+
* @return Persistent string containing the generated glossary
70+
*/
71+
typedef const char *(*esp_command_glossary_t)(void *context);
72+
73+
/**
74+
* @brief Structure describing a console command
75+
*
76+
* @note The `group` field allows categorizing commands into groups,
77+
* which can simplify filtering or listing commands.
78+
*/
79+
typedef struct esp_command {
80+
const char *name; /*!< Name of the command */
81+
const char *group; /*!< Command group to which this command belongs */
82+
const char *help; /*!< Short help text for the command */
83+
esp_command_func_t func; /*!< Function implementing the command */
84+
void *func_ctx; /*!< User-defined context for the command function */
85+
esp_command_hint_t hint_cb; /*!< Callback returning the hint for the command */
86+
esp_command_glossary_t glossary_cb; /*!< Callback returning the glossary for the command */
87+
} esp_command_t;
88+
89+
/**
90+
* @brief Configuration parameters for esp_commands_manager initialization
91+
*/
92+
typedef struct esp_commands_config {
93+
uint32_t heap_caps_used; /*!< Set of heap capabilities to be used to perform internal allocations */
94+
size_t max_cmdline_length; /*!< Maximum length of the command line buffer, in bytes */
95+
size_t max_cmdline_args; /*!< Maximum number of command line arguments to parse */
96+
int hint_color; /*!< ANSI color code used for hint text */
97+
bool hint_bold; /*!< If true, display hint text in bold */
98+
} esp_commands_config_t;
99+
100+
/**
101+
* @brief Callback for a completed command name
102+
*
103+
* This callback is called when a command is successfully completed.
104+
*
105+
* @param cb_ctx Opaque pointer pointing at the context passed to the callback
106+
* @param completed_cmd_name Completed command name
107+
*/
108+
typedef void (*esp_command_get_completion_t)(void *cb_ctx, const char *completed_cmd_name);
109+
110+
/**
111+
* @brief Callback to retrieve a string field of esp_command_t
112+
*
113+
* @param cmd Command object
114+
* @return Value of the requested string field
115+
*/
116+
typedef const char *(*esp_commands_get_field_t)(const esp_command_t *cmd);
117+
118+
/**
119+
* @brief Opaque handle to a set of commands
120+
*/
121+
typedef struct esp_command_sets *esp_command_set_handle_t;
122+
123+
/**
124+
* @brief Macro to define a forced inline accessor for a string field of esp_command_t
125+
*
126+
* @param NAME Field name of the esp_command_t structure
127+
*/
128+
#define DEFINE_FIELD_ACCESSOR(NAME) \
129+
static inline __attribute__((always_inline)) \
130+
const char *get_##NAME(const esp_command_t *cmd) { \
131+
if (!cmd) { \
132+
return NULL; \
133+
} \
134+
return cmd->NAME; \
135+
}
136+
137+
/**
138+
* @brief Macro expanding to
139+
* static inline __attribute__((always_inline)) const char *get_name(esp_command_t *cmd) {
140+
* if (!cmd) {
141+
* return NULL;
142+
* }
143+
* return cmd->name;
144+
* }
145+
*/
146+
DEFINE_FIELD_ACCESSOR(name)
147+
148+
/**
149+
* @brief Macro expanding to
150+
* static inline __attribute__((always_inline)) const char *get_group(esp_command_t *cmd) {
151+
* if (!cmd) {
152+
* return NULL;
153+
* }
154+
* return cmd->group;
155+
* }
156+
*/
157+
DEFINE_FIELD_ACCESSOR(group)
158+
159+
/**
160+
* @brief Macro expanding to
161+
* static inline __attribute__((always_inline)) const char *get_help(esp_command_t *cmd) {
162+
* if (!cmd) {
163+
* return NULL;
164+
* }
165+
* return cmd->help;
166+
* }
167+
*/
168+
DEFINE_FIELD_ACCESSOR(help)
169+
170+
/**
171+
* @brief Macro to create the accessor function name for a field of esp_command_t
172+
*
173+
* @note Those accessor functions are defined in esp_commands_internal.h
174+
*
175+
* @param NAME Field name of esp_command_t
176+
*/
177+
#define FIELD_ACCESSOR(NAME) get_##NAME
178+
179+
#ifdef __cplusplus
180+
}
181+
#endif

esp_commands/test_apps/pytest_esp_commands.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,6 @@
1010
not bool(glob.glob(f'{Path(__file__).parent.absolute()}/build*/')),
1111
reason="Skip the idf version that did not build"
1212
)
13-
@idf_parametrize('target', ['linux'], indirect=['target'])
13+
@idf_parametrize('target', ['linux', 'esp32'], indirect=['target'])
1414
def test_esp_commands(dut) -> None:
1515
dut.run_all_single_board_cases()

0 commit comments

Comments
 (0)