TCP 的逻辑实现,可以和客户端连接发送数据

This commit is contained in:
2026-03-04 10:29:20 +08:00
parent f32d91c424
commit f45b571162
16 changed files with 14027 additions and 2 deletions

164
src/menu.c Normal file
View File

@@ -0,0 +1,164 @@
#include "menu.h"
#include <stdio.h>
#include <string.h>
/* 简单的静态菜单树:
*
* 层级 0: [运行界面] [定值设置] [查看数据]
* │ │
* 层级 1: (子菜单...) (子菜单...)
*/
static MenuItem g_menuRun;
static MenuItem g_menuSet;
static MenuItem g_menuSee;
static MenuItem g_menuSet1;
static MenuItem g_menuSet2;
void Menu_InitPC(MenuCtrl *ctrl)
{
memset(&g_menuRun, 0, sizeof(g_menuRun));
memset(&g_menuSet, 0, sizeof(g_menuSet));
memset(&g_menuSee, 0, sizeof(g_menuSee));
memset(&g_menuSet1, 0, sizeof(g_menuSet1));
memset(&g_menuSet2, 0, sizeof(g_menuSet2));
/* 0 级菜单 */
g_menuRun.name = "运行界面";
g_menuRun.tip = "显示运行状态";
g_menuRun.level = 0;
g_menuRun.pos = 0;
g_menuSet.name = "定值设置";
g_menuSet.tip = "进入定值设置菜单";
g_menuSet.level = 0;
g_menuSet.pos = 1;
g_menuSee.name = "查看数据";
g_menuSee.tip = "查看测量值和记录";
g_menuSee.level = 0;
g_menuSee.pos = 2;
/* 0 级链表关系 */
g_menuRun.before = &g_menuSee;
g_menuRun.behind = &g_menuSet;
g_menuSet.before = &g_menuRun;
g_menuSet.behind = &g_menuSee;
g_menuSee.before = &g_menuSet;
g_menuSee.behind = &g_menuRun;
/* 1 级菜单:定值设置下的两个子菜单 */
g_menuSet1.name = "保护定值";
g_menuSet1.tip = "编辑保护定值";
g_menuSet1.level = 1;
g_menuSet1.pos = 0;
g_menuSet1.higher = &g_menuSet;
g_menuSet2.name = "通信参数";
g_menuSet2.tip = "编辑通信参数";
g_menuSet2.level = 1;
g_menuSet2.pos = 1;
g_menuSet2.higher = &g_menuSet;
g_menuSet1.before = &g_menuSet2;
g_menuSet1.behind = &g_menuSet2;
g_menuSet2.before = &g_menuSet1;
g_menuSet2.behind = &g_menuSet1;
g_menuSet.lower = &g_menuSet1;
/* 初始化控制结构 */
ctrl->head0 = &g_menuRun;
ctrl->current = &g_menuRun;
}
/* 控制台绘制当前菜单状态 */
static void Menu_Draw(const MenuCtrl *ctrl)
{
const MenuItem *cur = ctrl->current;
const MenuItem *p;
printf("\n==== PC HMI 菜单模拟 ====\n");
printf("使用 W/S/A/D/Enter/Esc 操作Ctrl+C 退出。\n\n");
/* 显示 0 级菜单 */
printf("[0级菜单]: ");
p = ctrl->head0;
if (!p) {
printf("(空)\n");
return;
}
const MenuItem *start = p;
do {
if (p == cur)
printf(" [*%s*] ", p->name);
else
printf(" %s ", p->name);
p = p->behind;
} while (p && p != start);
printf("\n");
/* 若当前有下级,则显示 1 级菜单 */
if (cur->lower) {
printf(" 子菜单:\n");
p = cur->lower;
start = p;
do {
printf(" - %s\n", p->name);
p = p->behind;
} while (p && p != start);
}
/* 提示信息 */
printf("\n提示: %s\n", cur->tip ? cur->tip : "");
}
void Menu_LoopStep(MenuCtrl *ctrl, int key)
{
MenuItem *cur = ctrl->current;
switch (key) {
case KEY_U:
if (cur->before)
cur = cur->before;
break;
case KEY_D:
if (cur->behind)
cur = cur->behind;
break;
case KEY_L:
if (cur->higher)
cur = cur->higher;
break;
case KEY_R:
case KEY_ENT:
if (cur->lower)
cur = cur->lower;
printf("\n>>> 进入 [%s] 功能(模拟用户层)...\n", cur->name);
break;
case KEY_ESC:
if (cur->higher)
cur = cur->higher;
break;
default:
break;
}
ctrl->current = cur;
Menu_Draw(ctrl);
}
int Menu_MapKey(int ch)
{
if (ch == 'w' || ch == 'W') return KEY_U;
if (ch == 's' || ch == 'S') return KEY_D;
if (ch == 'a' || ch == 'A') return KEY_L;
if (ch == 'd' || ch == 'D') return KEY_R;
if (ch == '\r' || ch == '\n') return KEY_ENT;
if (ch == 27) return KEY_ESC; /* ESC */
return KEY_NONE;
}