diff --git a/src/system/RTU/src/app_config.json b/config/SYSTEM/app_config.json similarity index 100% rename from src/system/RTU/src/app_config.json rename to config/SYSTEM/app_config.json diff --git a/release/src/system/RTU/makefile b/release/src/system/RTU/makefile index b37fcaf..9e9d8ad 100644 --- a/release/src/system/RTU/makefile +++ b/release/src/system/RTU/makefile @@ -25,7 +25,8 @@ S := $(ROOT)/src/system/RTU/src C_OBJ := $(CURDIR)/RTU/obj/main.o CXX_OBJ := $(CURDIR)/RTU/obj/app_sys.o -.PHONY: all; all: $(O) +.PHONY: all clean rebuild +all: $(O) $(O): $(C_OBJ) $(CXX_OBJ) @mkdir -p $(dir $@) @@ -40,5 +41,7 @@ $(CXX_OBJ): $(S)/app_sys.cpp @mkdir -p $(dir $@) $(CXX) $(CXX_FLAGS) $(INC_PATH) -c $< -o $@ -.PHONY: clean; clean: +clean: rm -rf $(CURDIR)/RTU/obj $(O) + +rebuild: clean all diff --git a/src/system/RTU/src/app_sys.cpp b/src/system/RTU/src/app_sys.cpp index 0161f55..79bd362 100644 --- a/src/system/RTU/src/app_sys.cpp +++ b/src/system/RTU/src/app_sys.cpp @@ -1,9 +1,16 @@ /** * @file app_sys.cpp * @brief 应用系统初始化 — X-Macro 驱动 + app_config.json 启停控制 - * @details 读取 config/SYSTEM/app_config.json 决定哪些模块启用, + * @details 运行时从 /config/SYSTEM/app_config.json 读取模块启停配置, * 通过 app_modules.h X-Macro 自动生成模块列表和 g_vec_app, * 为每个模块创建事件 + 3 级定时器 + 独立线程。 + * + * 配置文件目录结构: + * WORK_PATH/ (可执行文件所在目录) + * ├── RTU + * └── config/ + * └── SYSTEM/ + * └── app_config.json */ #include "mySystem.h" #include "myLog.h" @@ -19,6 +26,9 @@ /* ---- 启用的应用名集合(从 app_config.json 读取) ---- */ static std::set g_enabled_apps; +/* ---- 线程句柄(用于 stop 时 join) ---- */ +static std::vector g_threads; + /* ---- g_vec_app — 由 app_modules.h X-Macro 自动生成 ---- */ static std::vector g_vec_app = { @@ -32,23 +42,37 @@ static std::vector g_vec_app = /* ---- 三级定时器事件 ---- */ static uint32_t g_timer_event[TIMER_NUM] = {EV_TIMER1, EV_TIMER2, EV_TIMER3}; -/* ---- 获取系统配置目录路径 ---- */ +/* ---- 获取系统配置目录路径(优先级: WORK_PATH 环境变量 > 可执行文件所在目录) ---- */ static std::string get_system_config_path(void) { - char proc_dir[512] = {0}; - if (0 != func_proc_self_dir(proc_dir, sizeof(proc_dir))) + char buf[512] = {0}; + + /* 优先使用 WORK_PATH 环境变量(RK3568 装置运行时设置) */ + if (0 == func_get_work_path(buf, sizeof(buf))) + { + return std::string(buf) + "/config/SYSTEM/"; + } + + /* fallback: 从可执行文件路径推导(本地调试用) */ + if (0 != func_proc_self_dir(buf, sizeof(buf))) { LOG_E("func_proc_self_dir failed"); + return ""; } - return std::string(proc_dir) + "config/SYSTEM/"; + + return std::string(buf) + "/config/SYSTEM/"; } /* ---- 解析 app_config.json ---- */ static int app_config_load(void) { std::string path = get_system_config_path(); - if (path.empty()) { return -1; } + + if (path.empty()) + { + return -1; + } std::string cfg_path = path + "app_config.json"; @@ -60,9 +84,9 @@ static int app_config_load(void) /* 配置文件不存在时不视为错误——默认启用所有模块 */ LOG_I("app_config.json not found, enabling all modules by default"); - for (auto &app : g_vec_app) + for (size_t i = 0; i < g_vec_app.size(); i++) { - g_enabled_apps.insert(app.name); + g_enabled_apps.insert(g_vec_app[i].name); } return 0; @@ -74,27 +98,38 @@ static int app_config_load(void) if (!root) { LOG_E("cJSON_Parse failed for app_config.json"); + return -1; } cJSON *apps = cJSON_GetObjectItem(root, "apps"); + if (!apps || !cJSON_IsArray(apps)) { LOG_E("app_config.json missing 'apps' array"); cJSON_Delete(root); + return -1; } int arr_size = cJSON_GetArraySize(apps); + for (int i = 0; i < arr_size; i++) { cJSON *item = cJSON_GetArrayItem(apps, i); - if (!item) { continue; } + + if (!item) + { + continue; + } cJSON *name = cJSON_GetObjectItem(item, "name"); cJSON *enable = cJSON_GetObjectItem(item, "enable"); - if (!name || !cJSON_IsString(name)) { continue; } + if (!name || !cJSON_IsString(name)) + { + continue; + } if (enable && cJSON_IsTrue(enable)) { @@ -112,6 +147,7 @@ static int app_config_load(void) if (g_enabled_apps.empty()) { LOG_E("no apps enabled in config"); + return -1; } @@ -127,13 +163,19 @@ static bool is_app_enabled(const char *name) /* ---- 定时器回调:发送对应的定时器事件给模块 ---- */ static void app_timer_expire(void *arg) { - if (!arg) { return; } + if (!arg) + { + return; + } uint32_t signal = *(uint32_t *)arg; uint8_t thid = signal >> 8; uint8_t tm_id = signal & 0xFF; - if (thid >= g_vec_app.size() || tm_id >= TIMER_NUM) { return; } + if (thid >= g_vec_app.size() || tm_id >= TIMER_NUM) + { + return; + } task_event_send(g_vec_app[thid].p_event, g_timer_event[tm_id]); } @@ -141,7 +183,10 @@ static void app_timer_expire(void *arg) /* ---- 为一个模块创建 3 级定时器 ---- */ static int app_timer_create(stru_app *p_app) { - if (!p_app) { return -1; } + if (!p_app) + { + return -1; + } uint32_t delay_ms = 1; @@ -162,6 +207,7 @@ static int app_timer_create(stru_app *p_app) if (!p_app->p_timer[i]) { LOG_E("timer%d create failed for %s", i + 1, p_app->name); + return -1; } @@ -174,24 +220,29 @@ static int app_timer_create(stru_app *p_app) /* ---- 主初始化流程 ---- */ static int app_init(void) { - uint32_t i; + size_t i; /* init1: 信号注册前 */ for (i = 0; i < g_vec_app.size(); i++) { stru_app *p = &g_vec_app[i]; - if (!p->app_init1) { continue; } + if (!p->app_init1) + { + continue; + } if (!is_app_enabled(p->name)) { LOG_I("app skipped (disabled): %s", p->name); + continue; } if (0 != p->app_init1((void *)p)) { LOG_E("app_init1 failed: %s", p->name); + return -1; } } @@ -201,17 +252,22 @@ static int app_init(void) { stru_app *p = &g_vec_app[i]; - if (!p->app_init2) { continue; } + if (!p->app_init2) + { + continue; + } if (!is_app_enabled(p->name)) { LOG_I("app skipped (disabled): %s", p->name); + continue; } if (0 != p->app_init2((void *)p)) { LOG_E("app_init2 failed: %s", p->name); + return -1; } } @@ -224,10 +280,12 @@ static int app_init(void) p->app_id = i; std::string ev_name = "EV_" + std::string(p->name); + p->p_event = task_event_create(ev_name.c_str()); if (!p->p_event) { LOG_E("task_event_create failed: %s", ev_name.c_str()); + return -1; } @@ -236,12 +294,14 @@ static int app_init(void) if (0 != app_timer_create(p)) { LOG_E("app_timer_create failed: %s", p->name); + return -1; } if (!is_app_enabled(p->name)) { LOG_I("app skipped (disabled): %s", p->name); + continue; } @@ -250,10 +310,11 @@ static int app_init(void) if (0 != pthread_create(&thread, NULL, p->fun_cb, p->arg)) { LOG_E("pthread_create failed: %s", p->name); + return -1; } - pthread_detach(thread); + g_threads.push_back(thread); LOG_I("thread started: %s", p->name); task_sleep_ms(10); @@ -269,30 +330,62 @@ int app_sys_init(void) if (0 != app_config_load()) { LOG_E("app_config_load failed"); + return -1; } - if (g_vec_app.size() != ENUM_APP_MAX) + if (g_vec_app.size() != (size_t)ENUM_APP_MAX) { LOG_E("g_vec_app size mismatch: %zu vs ENUM %d", g_vec_app.size(), ENUM_APP_MAX); + return -1; } if (0 != app_init()) { LOG_E("app_init failed"); + return -1; } return 0; } +/** + * @brief 停止所有应用模块 + * @details 向每个模块发送 EV_STOP 信号,通知其退出主循环,然后 join 所有线程 + */ +void app_sys_stop(void) +{ + LOG_I("stopping all app modules..."); + + for (size_t i = 0; i < g_vec_app.size(); i++) + { + stru_app *p = &g_vec_app[i]; + + if (p->p_event) + { + task_event_send(p->p_event, EV_STOP); + } + } + + /* 等待所有线程退出 */ + for (size_t i = 0; i < g_threads.size(); i++) + { + pthread_join(g_threads[i], NULL); + LOG_I("module thread [%zu] exited", i); + } + + LOG_I("all app modules stopped"); +} + stru_app *app_get_ptr(uint32_t app_id) { if (app_id >= ENUM_APP_MAX) { LOG_E("app_id out of range: %u max %d", app_id, ENUM_APP_MAX); + return NULL; } diff --git a/src/system/RTU/src/main.c b/src/system/RTU/src/main.c index 1659374..1a2ec7d 100644 --- a/src/system/RTU/src/main.c +++ b/src/system/RTU/src/main.c @@ -3,6 +3,13 @@ * @brief RTU 主程序入口 * @details app_sys_init() 自动启动所有 X-Macro 注册的模块。 * 新增模块只需修改 src/system/inc/app_modules.h,无需改动本文件。 + * + * 配置文件约定: + * WORK_PATH/ (可执行文件所在目录,或 WORK_PATH 环境变量指定) + * ├── RTU + * └── config/ + * └── SYSTEM/ + * └── app_config.json */ #include "mySystem.h" #include "myLog.h" @@ -22,13 +29,14 @@ static void sig_handler(int sig) { (void)sig; g_running = 0; - LOG_I("signal received, shutting down..."); + 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, @@ -39,6 +47,7 @@ static void cmd_uptime(int argc, char *argv[]) { (void)argc; (void)argv; + printf("RTU uptime: (running)\n"); } @@ -64,6 +73,7 @@ int main(int argc, char *argv[]) if (app_sys_init() != 0) { LOG_E("app_sys_init failed, aborting"); + return 1; } @@ -73,7 +83,10 @@ int main(int argc, char *argv[]) { char *line = linenoise("RTU> "); - if (!line) { break; } + if (!line) + { + break; + } if (line[0] != '\0') { @@ -101,6 +114,8 @@ int main(int argc, char *argv[]) } LOG_I("shutting down..."); + + app_sys_stop(); dc_cleanup(); log_cleanup(); diff --git a/src/system/inc/mySystem.h b/src/system/inc/mySystem.h index da22518..44de101 100644 --- a/src/system/inc/mySystem.h +++ b/src/system/inc/mySystem.h @@ -24,6 +24,7 @@ extern "C" #define EV_TIMER1 (0x01 << 0) #define EV_TIMER2 (0x01 << 1) #define EV_TIMER3 (0x01 << 2) +#define EV_STOP (0x80) /**< 模块停止信号 */ #define MSG_SIZE 2048 @@ -76,8 +77,9 @@ stru_app *app_get_ptr(uint32_t app_id); #include "app_modules.h" #undef APP_MODULE -/* ---- 初始化 ---- */ -int app_sys_init(void); +/* ---- 初始化与停止 ---- */ +int app_sys_init(void); +void app_sys_stop(void); #ifdef __cplusplus }