main+libcmd: 清理终端交互,保留命令注册机制
- main.c: 去掉 getopt/linenoise/system() 命令行交互,改为纯事件等待循环 - main.c: app_sys_init() 后自动调用 dc_save_out_signals_xml() 导出信号 XML - libcmd: 精简头文件,去掉 Unix Socket/客户端代码 - libcmd: 保留 CMD_REGISTER 命令注册机制(被各模块使用) - libcmd: 保留 cmd_find/cmd_manager_get_commands(webserver 依赖)
This commit is contained in:
parent
b04cba095d
commit
62cf0cdc11
|
|
@ -1,8 +1,9 @@
|
|||
/**
|
||||
* @file myCmd.h
|
||||
* @brief 命令处理框架 — 纯 C 接口
|
||||
* @details 命令注册/分发/补全,内置 linenoise 行编辑。
|
||||
* @details 命令注册/分发/补全。
|
||||
* 通过 `__attribute__((constructor))` 实现模块自动注册。
|
||||
* 调试命令通过 WebSocket 在前端执行,不占用终端 stdin。
|
||||
*/
|
||||
#ifndef _MY_CMD_H_
|
||||
#define _MY_CMD_H_
|
||||
|
|
@ -42,21 +43,6 @@ void cmd_complete(const char *buf, char ***completions, int *ncomp);
|
|||
void cmd_sub_complete(const char *buf, char ***completions, int *ncomp,
|
||||
const char **subs, int sub_count);
|
||||
|
||||
/** 行编辑交互式输入 */
|
||||
char *linenoise(const char *prompt);
|
||||
|
||||
/** 释放 linenoise 返回的内存 */
|
||||
void linenoiseFree(void *ptr);
|
||||
|
||||
/** 添加历史记录 */
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
|
||||
/** 释放所有历史 */
|
||||
void linenoiseHistoryFree(void);
|
||||
|
||||
/** 设置自动补全回调 */
|
||||
void lineniseSetCompletionCallback(void (*cb)(const char *, char ***, int *));
|
||||
|
||||
/** 注册命令宏(无补全) */
|
||||
#define CMD_REGISTER(cmd_name, func_ptr, cmd_desc) \
|
||||
__attribute__((constructor)) static void register_##func_ptr(void) \
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@
|
|||
extern "C"
|
||||
{
|
||||
|
||||
/* ===== 内置命令 ===== */
|
||||
CMD_REGISTER("help", cmd_help, "显示所有可用命令")
|
||||
|
||||
/* ===== 命令注册表 ===== */
|
||||
|
||||
static std::vector<stru_cmd> &get_cmd_list(void)
|
||||
|
|
@ -182,6 +185,8 @@ void cmd_help(int argc, char *argv[])
|
|||
{
|
||||
printf("%-24s [%s]\n", cmd.name, cmd.desc);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* ===== 内置 linenoise ===== */
|
||||
|
|
@ -199,6 +204,7 @@ static void (*g_completion_cb)(const char *, char ***, int *) = NULL;
|
|||
|
||||
static struct termios g_orig_termios;
|
||||
static int g_raw_enabled = 0;
|
||||
static void (*g_old_sigint)(int) = NULL;
|
||||
|
||||
static void disable_raw(void)
|
||||
{
|
||||
|
|
@ -209,24 +215,31 @@ static void disable_raw(void)
|
|||
|
||||
tcsetattr(STDIN_FILENO, TCSAFLUSH, &g_orig_termios);
|
||||
g_raw_enabled = 0;
|
||||
|
||||
/* restore SIGINT handler */
|
||||
if (g_old_sigint)
|
||||
{
|
||||
signal(SIGINT, g_old_sigint);
|
||||
g_old_sigint = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void sigint_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
void (*old)(int) = g_old_sigint;
|
||||
|
||||
if (g_raw_enabled)
|
||||
disable_raw();
|
||||
|
||||
/* 先恢复 raw mode 再调用原始 handler(main.c 的 sig_handler 设 g_running=0) */
|
||||
if (old)
|
||||
{
|
||||
disable_raw();
|
||||
old(sig);
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static int enable_raw(void)
|
||||
{
|
||||
signal(SIGINT, sigint_handler);
|
||||
g_old_sigint = signal(SIGINT, sigint_handler);
|
||||
tcgetattr(STDIN_FILENO, &g_orig_termios);
|
||||
atexit(disable_raw);
|
||||
|
||||
|
|
@ -424,24 +437,48 @@ static int linenoise_edit(char *buf, int bufsize, const char *prompt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void linenoiseSetCompletionCallback(void (*cb)(const char *, char ***, int *))
|
||||
{
|
||||
g_completion_cb = cb;
|
||||
}
|
||||
|
||||
char *linenoise(const char *prompt)
|
||||
{
|
||||
char buf[1024];
|
||||
|
||||
/* 默认补全回调(首次调用或外部未设置时生效) */
|
||||
if (!g_completion_cb)
|
||||
{
|
||||
g_completion_cb = cmd_complete;
|
||||
}
|
||||
|
||||
if (0 != enable_raw())
|
||||
{
|
||||
return NULL;
|
||||
/* stdin is not a TTY (pipe/redirect) — fallback to fgets */
|
||||
if (prompt) SAFE_WRITE(STDOUT_FILENO, prompt, strlen(prompt));
|
||||
if (!fgets(buf, (int)sizeof(buf), stdin))
|
||||
{
|
||||
return NULL; /* EOF */
|
||||
}
|
||||
/* strip trailing newline */
|
||||
size_t len = strlen(buf);
|
||||
while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r'))
|
||||
{
|
||||
buf[--len] = '\0';
|
||||
}
|
||||
return strdup(buf);
|
||||
}
|
||||
|
||||
int n = linenoise_edit(buf, (int)sizeof(buf), prompt);
|
||||
|
||||
disable_raw();
|
||||
|
||||
if (n <= 0)
|
||||
if (n < 0)
|
||||
{
|
||||
return NULL;
|
||||
return NULL; /* read error or EOF */
|
||||
}
|
||||
|
||||
/* empty line: return allocated empty string (not NULL) */
|
||||
char *copy = strdup(buf);
|
||||
|
||||
return copy;
|
||||
|
|
@ -471,6 +508,8 @@ void linenoiseHistoryFree(void)
|
|||
{
|
||||
free(g_history[j]);
|
||||
}
|
||||
|
||||
g_history_len = 0;
|
||||
}
|
||||
|
||||
void lineniseSetCompletionCallback(void (*cb)(const char *, char ***, int *))
|
||||
|
|
|
|||
|
|
@ -14,46 +14,21 @@
|
|||
#include "mySystem.h"
|
||||
#include "myLog.h"
|
||||
#include "myDatacenter.h"
|
||||
#include "myModbus.h"
|
||||
#include "myFunc.h"
|
||||
#include "myCmd.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
static volatile int g_running = 1;
|
||||
|
||||
static void sig_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
g_running = 0;
|
||||
LOG_I("signal %d received, shutting down...", sig);
|
||||
}
|
||||
|
||||
static void cmd_version(int argc, char *argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
printf("RTU_ALL_AI v1.0\n");
|
||||
printf(" libmodbus v%d.%d.%d\n",
|
||||
libmodbus_version_major, libmodbus_version_minor,
|
||||
libmodbus_version_micro);
|
||||
}
|
||||
|
||||
static void cmd_uptime(int argc, char *argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
printf("RTU uptime: (running)\n");
|
||||
}
|
||||
|
||||
CMD_REGISTER("version", cmd_version, "show firmware version");
|
||||
CMD_REGISTER("uptime", cmd_uptime, "show uptime");
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
(void)argc;
|
||||
|
|
@ -65,11 +40,13 @@ int main(int argc, char *argv[])
|
|||
signal(SIGTERM, sig_handler);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
/* 日志初始化:控制台输出(调试可见),运行时可开文件输出 */
|
||||
log_init(NULL);
|
||||
LOG_I("RTU booting...");
|
||||
|
||||
/* 启动数据中心 */
|
||||
dc_init(NULL);
|
||||
|
||||
/* X-Macro 驱动启动所有模块 */
|
||||
if (app_sys_init() != 0)
|
||||
{
|
||||
LOG_E("app_sys_init failed, aborting");
|
||||
|
|
@ -79,38 +56,25 @@ int main(int argc, char *argv[])
|
|||
|
||||
LOG_I("RTU running");
|
||||
|
||||
/* 导出 out 信号 XML 供前端 PLC Config 页面使用(所有模块 init1/init2 之后) */
|
||||
{
|
||||
char proc_dir[256] = {0};
|
||||
|
||||
if (0 == func_proc_self_dir(proc_dir, sizeof(proc_dir)))
|
||||
{
|
||||
char xml_path[512];
|
||||
|
||||
snprintf(xml_path, sizeof(xml_path), "%s/config/SYSTEM/datacenter_out.xml",
|
||||
proc_dir);
|
||||
dc_save_out_signals_xml(xml_path);
|
||||
LOG_I("datacenter_out.xml exported to %s", xml_path);
|
||||
}
|
||||
}
|
||||
|
||||
/* 纯事件等待,命令交互走 Web 前端 */
|
||||
while (g_running)
|
||||
{
|
||||
char *line = linenoise("RTU> ");
|
||||
|
||||
if (!line)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (line[0] != '\0')
|
||||
{
|
||||
linenoiseHistoryAdd(line);
|
||||
|
||||
char *argv_buf[16];
|
||||
uint8_t argc = 0;
|
||||
|
||||
if (func_str2argv(line, &argc, argv_buf, 16) == 0 && argc > 0)
|
||||
{
|
||||
stru_cmd *cmd = cmd_find(argv_buf[0]);
|
||||
|
||||
if (cmd)
|
||||
{
|
||||
cmd->func((int)argc, argv_buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("unknown command: %s (type 'help')\n", argv_buf[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
linenoiseFree(line);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
LOG_I("shutting down...");
|
||||
|
|
|
|||
Loading…
Reference in New Issue