编程技术分享

分享编程知识,探讨技术创新

0%

简介:简单的 KVM 控制卡,

好的,作为一名高级嵌入式软件开发工程师,我将根据你提供的嵌入式产品图片(简单的 KVM 控制卡)和需求,详细说明最适合的代码设计架构,并提供具体的 C 代码实现方案。这个方案将涵盖嵌入式系统开发的完整流程,从需求分析到系统实现,再到测试验证和维护升级,旨在建立一个可靠、高效、可扩展的系统平台。
关注微信公众号,提前获取相关推文

项目背景:简单的 KVM 控制卡

KVM (Keyboard, Video, Mouse) 控制卡允许用户通过一套键盘、显示器和鼠标控制多台计算机。简单的 KVM 控制卡,如图片所示,通常用于家庭或小型办公室环境,方便用户管理少量服务器或电脑。

需求分析

  1. 功能性需求:

    • 键盘鼠标控制: 能够捕获 USB 键盘和鼠标的输入,并将这些输入信号传输到目标计算机。同时,能够接收来自目标计算机的键盘和鼠标反馈信号,并传递给本地的键盘和鼠标。
    • 视频信号切换: 能够切换不同目标计算机的视频信号输出到本地显示器。支持常见的视频接口,例如 HDMI 或 VGA(根据实际硬件设计)。
    • 目标计算机选择: 提供一种机制来选择当前要控制的目标计算机。这可以通过按钮、拨码开关或更复杂的软件界面实现。
    • 热键切换 (可选): 允许用户通过特定的键盘快捷键组合来切换目标计算机。
    • 音频支持 (可选): 如果硬件支持,可以考虑音频信号的切换和传输。
    • 即插即用: 用户连接设备后应能快速识别并开始工作,无需复杂的配置。
  2. 非功能性需求:

    • 可靠性: 系统必须稳定可靠,能够长时间无故障运行。
    • 高效性: 输入输出延迟要尽可能低,保证良好的用户体验。
    • 低功耗: 作为嵌入式设备,功耗应控制在合理范围内。
    • 可扩展性: 代码架构应易于扩展,方便未来添加新功能或支持更多目标计算机。
    • 易维护性: 代码应结构清晰,注释完善,方便维护和升级。
    • 安全性: 虽然是简单的 KVM,但也要考虑基本的安全性,例如防止未授权访问 (如果未来考虑网络功能)。

系统架构设计

为了满足以上需求,并考虑到嵌入式系统的特点,我将采用分层架构来设计 KVM 控制卡的软件系统。分层架构具有良好的模块化特性,易于理解、开发、测试和维护。

系统架构可以分为以下几个层次:

  1. 硬件抽象层 (HAL - Hardware Abstraction Layer):

    • 作用:屏蔽底层硬件差异,向上层提供统一的硬件接口。
    • 模块:
      • GPIO 驱动: 控制 GPIO 引脚,用于按钮检测、LED 控制等。
      • USB 驱动: 处理 USB 接口的通信,包括 USB Host 和 USB Device 模式。
      • 视频接口驱动: 处理视频输入和输出,例如 HDMI 或 VGA 控制器驱动。
      • 定时器驱动: 提供定时器功能,用于系统时钟、延时等。
      • 中断控制器驱动: 管理中断,响应硬件中断事件。
      • 存储器驱动: 如果需要,管理 Flash 或其他存储器。
  2. 板级支持包 (BSP - Board Support Package):

    • 作用:为特定的硬件平台提供基础支持,包括芯片初始化、时钟配置、外设初始化等。
    • 模块:
      • 系统初始化: 芯片启动代码,初始化系统时钟、中断向量表等。
      • 外设初始化: 初始化 GPIO、USB、视频接口等外设。
      • 时钟管理: 配置和管理系统时钟。
      • 电源管理: 如果需要,实现低功耗模式管理。
  3. 操作系统层 (OS Layer - 可选,对于简单 KVM 可以使用裸机系统):

    • 作用:提供任务调度、资源管理、进程间通信等功能。

    • 模块:

      • 任务调度器 (Scheduler): 如果使用 RTOS,负责任务的调度和切换。
      • 内存管理 (Memory Management): 分配和释放内存资源。
      • 同步机制 (Synchronization): 提供互斥锁、信号量等同步机制,用于任务间同步。
      • 消息队列 (Message Queue): 用于任务间消息传递。
    • 对于简单的 KVM 控制卡,为了降低复杂度和资源占用,可以使用裸机系统 (Bare-metal system) 而不使用 RTOS。 在裸机系统中,程序直接运行在硬件之上,没有操作系统的任务调度和资源管理,但需要开发者自己管理任务的调度和资源。对于简单的实时性要求不高的 KVM,裸机系统是可行的。 如果未来功能复杂化,可以考虑迁移到 RTOS。

  4. 核心服务层 (Core Service Layer):

    • 作用:实现 KVM 控制卡的核心功能,包括 USB 输入处理、视频切换控制、目标计算机管理等。
    • 模块:
      • USB 输入处理模块:
        • 键盘输入处理: 解析 USB 键盘数据,识别按键事件,并将按键事件转发到目标计算机或本地系统。
        • 鼠标输入处理: 解析 USB 鼠标数据,识别鼠标移动和按键事件,并将鼠标事件转发到目标计算机或本地系统。
      • 视频切换控制模块:
        • 视频输入捕获: 从视频输入接口(例如 HDMI 输入)捕获视频数据。
        • 视频输出控制: 控制视频输出接口(例如 HDMI 输出)的显示内容,实现视频切换。
      • 目标计算机管理模块:
        • 目标计算机状态管理: 记录当前连接的目标计算机状态。
        • 目标计算机切换逻辑: 根据用户输入(按钮、热键等)切换目标计算机。
      • 配置管理模块:
        • 系统配置加载: 从 Flash 或其他存储器加载系统配置参数。
        • 配置参数存储: 存储系统配置参数。
  5. 应用层 (Application Layer):

    • 作用:提供用户交互界面和系统控制逻辑。
    • 模块:
      • 用户界面模块: 处理用户输入,例如按钮按下、热键检测等。
      • 系统控制模块: 协调各个核心服务模块,实现 KVM 的整体功能。
      • 状态指示模块: 控制 LED 指示灯,显示系统状态和目标计算机状态。

技术选型与实践方法

  • 微控制器 (MCU): 根据 KVM 的功能需求和成本考虑,可以选择基于 ARM Cortex-M 系列的 MCU,例如 STM32 系列、NXP LPC 系列、或国产 MCU 如 GD32 系列。这些 MCU 具有丰富的外设接口(USB Host/Device, HDMI/VGA 控制器, GPIO, 定时器等),性能足够满足简单的 KVM 需求,并且成本相对较低。
  • USB 控制器: MCU 需要带有 USB Host 和 USB Device 控制器。USB Host 用于连接键盘和鼠标,USB Device 用于连接到目标计算机(作为 USB 设备)。
  • 视频接口: 根据硬件设计,选择合适的视频接口,例如 HDMI 或 VGA。如果选择 HDMI,则需要 MCU 带有 HDMI 控制器或外接 HDMI 芯片。
  • 开发工具:
    • 集成开发环境 (IDE): Keil MDK, IAR Embedded Workbench, STM32CubeIDE (如果选择 STM32) 等。
    • 编译器: ARM GCC 或 IDE 自带的编译器。
    • 调试器: JTAG/SWD 调试器。
    • 版本控制: Git。
  • 编程语言: C 语言 (嵌入式系统开发的首选语言)。
  • 开发方法:
    • 模块化开发: 按照分层架构进行模块化设计和开发。
    • 迭代开发: 从小功能开始,逐步迭代增加功能,并进行测试和验证。
    • 代码审查: 进行代码审查,保证代码质量。
    • 单元测试: 对关键模块进行单元测试,确保模块功能的正确性。
    • 集成测试: 进行模块集成测试,验证模块之间的协同工作。
    • 系统测试: 进行系统级测试,验证 KVM 的整体功能和性能。
    • 实践验证: 所有技术和方法都应经过实践验证,例如 USB 通信、视频切换、按键处理等都需要在实际硬件上进行测试和验证。

详细 C 代码实现 (框架和关键模块示例)

为了达到 3000 行代码的目标,并详细展示嵌入式 KVM 的实现,我将提供以下 C 代码示例,涵盖各个层次的关键模块,并添加详细的注释。 由于篇幅限制,我无法在此处完整提供 3000 行代码,但我会尽力提供详细的框架和关键模块的实现,并解释代码逻辑。

1. 硬件抽象层 (HAL)

hal_gpio.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef HAL_GPIO_H
#define HAL_GPIO_H

typedef enum {
GPIO_PIN_0,
GPIO_PIN_1,
GPIO_PIN_2,
// ... 定义更多 GPIO 引脚
GPIO_PIN_MAX
} gpio_pin_t;

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT
} gpio_mode_t;

typedef enum {
GPIO_LEVEL_LOW,
GPIO_LEVEL_HIGH
} gpio_level_t;

// 初始化 GPIO 引脚
void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode);

// 设置 GPIO 引脚输出电平
void hal_gpio_write(gpio_pin_t pin, gpio_level_t level);

// 读取 GPIO 引脚输入电平
gpio_level_t hal_gpio_read(gpio_pin_t pin);

#endif // HAL_GPIO_H

hal_gpio.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include "hal_gpio.h"
#include "platform_hardware.h" // 假设 platform_hardware.h 中定义了硬件相关的寄存器地址

void hal_gpio_init(gpio_pin_t pin, gpio_mode_t mode) {
// 根据 pin 和 mode 配置 GPIO 寄存器
// 具体的寄存器操作需要参考 MCU 的 datasheet 和硬件平台定义
if (mode == GPIO_MODE_INPUT) {
// 配置为输入模式,例如设置方向寄存器
// ... (硬件相关的寄存器操作)
platform_gpio_set_input_mode(pin);
} else if (mode == GPIO_MODE_OUTPUT) {
// 配置为输出模式,例如设置方向寄存器
// ... (硬件相关的寄存器操作)
platform_gpio_set_output_mode(pin);
}
}

void hal_gpio_write(gpio_pin_t pin, gpio_level_t level) {
// 设置 GPIO 输出电平
if (level == GPIO_LEVEL_HIGH) {
// 设置为高电平,例如设置输出数据寄存器
// ... (硬件相关的寄存器操作)
platform_gpio_set_high(pin);
} else if (level == GPIO_LEVEL_LOW) {
// 设置为低电平,例如设置输出数据寄存器
// ... (硬件相关的寄存器操作)
platform_gpio_set_low(pin);
}
}

gpio_level_t hal_gpio_read(gpio_pin_t pin) {
// 读取 GPIO 输入电平
// ... (硬件相关的寄存器操作)
if (platform_gpio_is_high(pin)) {
return GPIO_LEVEL_HIGH;
} else {
return GPIO_LEVEL_LOW;
}
}

hal_usb.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef HAL_USB_H
#define HAL_USB_H

// USB Host 相关定义
typedef enum {
USB_HOST_STATE_IDLE,
USB_HOST_STATE_ENUMERATING,
USB_HOST_STATE_READY,
USB_HOST_STATE_ERROR
} usb_host_state_t;

usb_host_state_t hal_usb_host_init();
usb_host_state_t hal_usb_host_get_state();
// ... 其他 USB Host 相关函数,例如发送/接收数据等

// USB Device 相关定义
typedef enum {
USB_DEVICE_STATE_DISCONNECTED,
USB_DEVICE_STATE_CONFIGURED,
USB_DEVICE_STATE_ERROR
} usb_device_state_t;

usb_device_state_t hal_usb_device_init();
usb_device_state_t hal_usb_device_get_state();
// ... 其他 USB Device 相关函数,例如发送/接收数据等

#endif // HAL_USB_H

hal_usb.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "hal_usb.h"
#include "platform_hardware.h" // 假设 platform_hardware.h 中定义了硬件相关的 USB 寄存器地址

// USB Host 初始化
usb_host_state_t hal_usb_host_init() {
// 初始化 USB Host 控制器
// ... (硬件相关的寄存器操作,例如使能时钟,配置寄存器)
platform_usb_host_enable_clock();
platform_usb_host_reset();
platform_usb_host_configure();

// 返回初始状态
return USB_HOST_STATE_IDLE;
}

usb_host_state_t hal_usb_host_get_state() {
// 获取 USB Host 状态
// ... (读取 USB Host 状态寄存器)
return USB_HOST_STATE_READY; // 假设已经初始化完成
}

// USB Device 初始化
usb_device_state_t hal_usb_device_init() {
// 初始化 USB Device 控制器
// ... (硬件相关的寄存器操作)
platform_usb_device_enable_clock();
platform_usb_device_reset();
platform_usb_device_configure();

// 返回初始状态
return USB_DEVICE_STATE_DISCONNECTED;
}

usb_device_state_t hal_usb_device_get_state() {
// 获取 USB Device 状态
// ... (读取 USB Device 状态寄存器)
return USB_DEVICE_STATE_CONFIGURED; // 假设已经配置完成
}

hal_video.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef HAL_VIDEO_H
#define HAL_VIDEO_H

// 视频接口相关定义 (以 HDMI 为例)
typedef enum {
VIDEO_RESOLUTION_1080P,
VIDEO_RESOLUTION_720P,
// ... 其他分辨率
} video_resolution_t;

typedef enum {
VIDEO_INPUT_SOURCE_1,
VIDEO_INPUT_SOURCE_2,
// ... 其他输入源
} video_input_source_t;

typedef enum {
VIDEO_OUTPUT_DEST_DISPLAY,
// ... 其他输出目的地
} video_output_dest_t;

void hal_video_init();
void hal_video_set_resolution(video_resolution_t resolution);
void hal_video_select_input_source(video_input_source_t source);
void hal_video_set_output_destination(video_output_dest_t dest);

#endif // HAL_VIDEO_H

hal_video.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include "hal_video.h"
#include "platform_hardware.h" // 假设 platform_hardware.h 中定义了硬件相关的视频寄存器地址

void hal_video_init() {
// 初始化视频控制器 (例如 HDMI 控制器)
// ... (硬件相关的寄存器操作)
platform_video_enable_clock();
platform_video_reset();
platform_video_configure();
}

void hal_video_set_resolution(video_resolution_t resolution) {
// 设置视频分辨率
// ... (根据 resolution 设置视频控制器的分辨率寄存器)
switch (resolution) {
case VIDEO_RESOLUTION_1080P:
platform_video_set_1080p_resolution();
break;
case VIDEO_RESOLUTION_720P:
platform_video_set_720p_resolution();
break;
// ... 其他分辨率处理
default:
// 默认分辨率处理
break;
}
}

void hal_video_select_input_source(video_input_source_t source) {
// 选择视频输入源
// ... (根据 source 设置视频控制器的输入源选择寄存器)
switch (source) {
case VIDEO_INPUT_SOURCE_1:
platform_video_select_input_source_1();
break;
case VIDEO_INPUT_SOURCE_2:
platform_video_select_input_source_2();
break;
// ... 其他输入源处理
default:
// 默认输入源处理
break;
}
}

void hal_video_set_output_destination(video_output_dest_t dest) {
// 设置视频输出目的地
// ... (根据 dest 设置视频控制器的输出目的地选择寄存器)
if (dest == VIDEO_OUTPUT_DEST_DISPLAY) {
platform_video_set_output_to_display();
}
// ... 其他输出目的地处理
}

2. 板级支持包 (BSP)

bsp.h:

1
2
3
4
5
6
#ifndef BSP_H
#define BSP_H

void bsp_init(); // 初始化所有板级资源

#endif // BSP_H

bsp.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "bsp.h"
#include "hal_gpio.h"
#include "hal_usb.h"
#include "hal_video.h"
#include "platform_hardware.h" // 假设 platform_hardware.h 中定义了硬件平台相关的配置

void bsp_init() {
// 系统时钟初始化 (根据具体 MCU 和硬件平台配置)
platform_system_clock_init();

// GPIO 初始化
hal_gpio_init(GPIO_PIN_LED1, GPIO_MODE_OUTPUT); // 假设 LED1 连接到 GPIO_PIN_LED1
hal_gpio_init(GPIO_PIN_BUTTON1, GPIO_MODE_INPUT); // 假设 BUTTON1 连接到 GPIO_PIN_BUTTON1

// USB Host 初始化
hal_usb_host_init();

// USB Device 初始化
hal_usb_device_init();

// 视频接口初始化
hal_video_init();
hal_video_set_resolution(VIDEO_RESOLUTION_1080P); // 默认分辨率

// 其他外设初始化...
}

3. 核心服务层 (Core Service Layer)

kvm_input.h:

1
2
3
4
5
6
7
8
9
10
#ifndef KVM_INPUT_H
#define KVM_INPUT_H

// 键盘和鼠标输入处理相关函数声明

void kvm_input_init();
void kvm_keyboard_process_data(uint8_t *data, uint32_t len); // 处理键盘输入数据
void kvm_mouse_process_data(uint8_t *data, uint32_t len); // 处理鼠标输入数据

#endif // KVM_INPUT_H

kvm_input.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include "kvm_input.h"
#include "hal_usb.h"
#include "usb_host_keyboard.h" // 假设有 USB Host 键盘驱动
#include "usb_host_mouse.h" // 假设有 USB Host 鼠标驱动
#include "usb_host.h" // 假设有通用的 USB Host 驱动接口

void kvm_input_init() {
// 初始化 USB Host 键盘和鼠标驱动
usb_host_keyboard_init();
usb_host_mouse_init();
}

void kvm_keyboard_process_data(uint8_t *data, uint32_t len) {
// 解析键盘数据 (需要根据 USB HID 键盘协议进行解析)
usb_keyboard_report_t keyboard_report;
if (usb_host_keyboard_parse_report(data, len, &keyboard_report) == USB_HOST_OK) {
// 将键盘事件转发到目标计算机 (通过 USB Device 发送)
// ... (将 keyboard_report 转换为 USB Device 键盘报告并发送)
usb_device_send_keyboard_report(&keyboard_report);
} else {
// 解析错误处理
// ...
}
}

void kvm_mouse_process_data(uint8_t *data, uint32_t len) {
// 解析鼠标数据 (需要根据 USB HID 鼠标协议进行解析)
usb_mouse_report_t mouse_report;
if (usb_host_mouse_parse_report(data, len, &mouse_report) == USB_HOST_OK) {
// 将鼠标事件转发到目标计算机 (通过 USB Device 发送)
// ... (将 mouse_report 转换为 USB Device 鼠标报告并发送)
usb_device_send_mouse_report(&mouse_report);
} else {
// 解析错误处理
// ...
}
}

// 假设的 USB Host 键盘驱动 (usb_host_keyboard.h 和 usb_host_keyboard.c)
// 这部分代码需要根据实际的 USB Host 驱动实现,这里仅为示例
// ... (USB Host 键盘驱动的头文件和源文件)

// 假设的 USB Host 鼠标驱动 (usb_host_mouse.h 和 usb_host_mouse.c)
// 这部分代码需要根据实际的 USB Host 驱动实现,这里仅为示例
// ... (USB Host 鼠标驱动的头文件和源文件)

// 假设的 USB Device 键盘和鼠标报告发送函数 (usb_device.h 和 usb_device.c)
// 这部分代码需要根据实际的 USB Device 驱动实现,这里仅为示例
// ... (USB Device 驱动的头文件和源文件,包含 usb_device_send_keyboard_report 和 usb_device_send_mouse_report 函数)

kvm_video.h:

1
2
3
4
5
6
7
8
9
#ifndef KVM_VIDEO_H
#define KVM_VIDEO_H

// 视频切换控制相关函数声明

void kvm_video_init();
void kvm_video_switch_input(uint8_t input_index); // 切换视频输入源

#endif // KVM_VIDEO_H

kvm_video.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "kvm_video.h"
#include "hal_video.h"

void kvm_video_init() {
// 初始化视频控制模块
hal_video_init();
}

void kvm_video_switch_input(uint8_t input_index) {
// 根据 input_index 切换视频输入源
switch (input_index) {
case 0:
hal_video_select_input_source(VIDEO_INPUT_SOURCE_1);
break;
case 1:
hal_video_select_input_source(VIDEO_INPUT_SOURCE_2);
break;
// ... 其他输入源处理
default:
// 默认输入源处理
hal_video_select_input_source(VIDEO_INPUT_SOURCE_1);
break;
}
}

kvm_target_mgmt.h:

1
2
3
4
5
6
7
8
9
10
#ifndef KVM_TARGET_MGMT_H
#define KVM_TARGET_MGMT_H

// 目标计算机管理相关函数声明

void kvm_target_mgmt_init();
void kvm_target_mgmt_select_target(uint8_t target_index); // 选择目标计算机
uint8_t kvm_target_mgmt_get_current_target(); // 获取当前目标计算机索引

#endif // KVM_TARGET_MGMT_H

kvm_target_mgmt.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "kvm_target_mgmt.h"
#include "hal_gpio.h"
#include "hal_video.h"
#include "kvm_input.h"

#define MAX_TARGET_COMPUTERS 2 // 假设最多支持 2 台目标计算机

static uint8_t current_target_index = 0; // 当前目标计算机索引

void kvm_target_mgmt_init() {
// 初始化目标计算机管理模块
current_target_index = 0; // 默认选择第一个目标计算机
kvm_video_switch_input(current_target_index); // 切换视频输入
// ... 初始化其他目标计算机相关状态
}

void kvm_target_mgmt_select_target(uint8_t target_index) {
if (target_index < MAX_TARGET_COMPUTERS) {
current_target_index = target_index;
kvm_video_switch_input(current_target_index); // 切换视频输入
// ... 更新其他目标计算机相关状态,例如 USB 连接切换 (如果需要硬件切换 USB 连接)
// ... 指示 LED 更新
}
}

uint8_t kvm_target_mgmt_get_current_target() {
return current_target_index;
}

4. 应用层 (Application Layer)

main.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "bsp.h"
#include "hal_gpio.h"
#include "kvm_input.h"
#include "kvm_video.h"
#include "kvm_target_mgmt.h"
#include "usb_host.h" // 假设有通用的 USB Host 驱动接口
#include "usb_device.h" // 假设有通用的 USB Device 驱动接口

int main() {
// 初始化板级支持包
bsp_init();

// 初始化 KVM 输入处理模块
kvm_input_init();

// 初始化 KVM 视频控制模块
kvm_video_init();

// 初始化目标计算机管理模块
kvm_target_mgmt_init();

// 初始化 USB Host 驱动
usb_host_init();

// 初始化 USB Device 驱动
usb_device_init();

// 主循环
while (1) {
// 检测按钮输入 (目标计算机切换)
if (hal_gpio_read(GPIO_PIN_BUTTON1) == GPIO_LEVEL_HIGH) {
// 按钮按下,切换目标计算机
uint8_t current_target = kvm_target_mgmt_get_current_target();
uint8_t next_target = (current_target + 1) % MAX_TARGET_COMPUTERS;
kvm_target_mgmt_select_target(next_target);
hal_gpio_write(GPIO_PIN_LED1, GPIO_LEVEL_HIGH); // 指示 LED 亮
// 简单的软件去抖动延时
for(volatile int i=0; i<100000; i++);
hal_gpio_write(GPIO_PIN_LED1, GPIO_LEVEL_LOW); // 指示 LED 灭
}

// 处理 USB Host 事件 (键盘和鼠标输入)
usb_host_process_events(); // 需要在 USB Host 驱动中实现事件处理,并调用 kvm_input_keyboard_process_data 和 kvm_input_mouse_process_data

// 处理 USB Device 事件 (目标计算机数据接收)
usb_device_process_events(); // 需要在 USB Device 驱动中实现事件处理

// 其他系统任务...
}

return 0;
}

5. 其他模块 (示例框架)

  • platform_hardware.h 和 platform_hardware.c: 平台相关的硬件定义和寄存器操作函数,需要根据具体的 MCU 和硬件平台实现。
  • usb_host 驱动 (usb_host.h, usb_host.c, usb_host_keyboard.h, usb_host_keyboard.c, usb_host_mouse.h, usb_host_mouse.c): USB Host 驱动,包括通用 USB Host 驱动框架,以及 USB HID 键盘和鼠标驱动的实现。可以使用现有的 USB Host 库,或者根据 USB 协议自行实现。
  • usb_device 驱动 (usb_device.h, usb_device.c): USB Device 驱动,用于模拟 USB 键盘和鼠标设备连接到目标计算机。可以使用现有的 USB Device 库,或者根据 USB 协议自行实现。

代码行数说明:

以上代码框架和示例代码虽然远未达到 3000 行,但这只是一个基础的框架。要达到 3000 行代码,需要:

  • 完善 HAL 层: HAL 层需要根据具体的 MCU 和硬件外设,编写详细的寄存器操作代码,以及错误处理、超时机制等。
  • 实现完整的 USB Host 和 USB Device 驱动: USB 驱动是嵌入式 KVM 的核心,需要实现 USB 总线枚举、设备识别、数据传输、协议解析等复杂逻辑。这部分代码量会很大,特别是如果需要自行实现 USB 协议栈。
  • 实现视频信号处理: 如果需要更复杂的视频处理功能,例如分辨率转换、帧率转换、视频叠加等,视频处理模块的代码量也会增加。
  • 添加更多功能: 例如热键切换、音频支持、网络控制 (如果未来扩展网络功能)、更复杂的配置管理、用户界面 (例如 OLED 显示屏上的菜单) 等,这些都会增加代码量。
  • 完善注释和文档: 为了代码的可读性和可维护性,需要添加详细的注释,并编写相关的开发文档。
  • 添加测试代码和测试用例: 为了保证代码质量,需要编写单元测试、集成测试和系统测试代码。

测试验证和维护升级

  1. 测试验证:

    • 单元测试: 针对 HAL 层、BSP 层、核心服务层中的关键函数和模块进行单元测试,例如 GPIO 驱动、USB 驱动的单元测试。
    • 集成测试: 测试各个模块之间的协同工作,例如 USB 输入处理模块和视频切换控制模块的集成测试。
    • 系统测试: 进行完整的 KVM 功能测试,包括键盘鼠标控制、视频切换、目标计算机选择等功能的测试。
    • 性能测试: 测试 KVM 的输入输出延迟、视频切换速度等性能指标。
    • 稳定性测试: 进行长时间的运行测试,验证系统的可靠性和稳定性。
    • 兼容性测试: 测试 KVM 与不同品牌、型号的键盘、鼠标、显示器和目标计算机的兼容性。
  2. 维护升级:

    • 模块化设计: 分层架构和模块化设计方便代码的维护和升级。
    • 版本控制: 使用 Git 进行代码版本控制,方便管理代码变更和回溯。
    • 固件升级机制: 预留固件升级接口,例如 USB DFU (Device Firmware Upgrade) 或 OTA (Over-The-Air) 升级 (如果支持网络功能)。
    • 错误日志记录: 添加错误日志记录功能,方便排查和解决问题。
    • 用户反馈收集: 收集用户反馈,了解用户需求和问题,持续改进产品。

总结

这个简单的 KVM 控制卡项目,虽然功能看似简单,但涉及到的嵌入式系统开发技术和流程是完整的。从需求分析、系统架构设计、详细的 C 代码实现框架、技术选型、实践方法、测试验证到维护升级,我都进行了详细的说明。

通过分层架构的设计,我们可以构建一个可靠、高效、可扩展的 KVM 系统平台。代码示例虽然只是框架,但展示了关键模块的实现思路和方法。在实际开发中,需要根据具体的硬件平台和功能需求,进一步完善代码实现,并进行充分的测试和验证。

希望这个详细的方案能够帮助你理解嵌入式 KVM 控制卡的开发过程,并为你提供一个良好的代码设计架构参考。

欢迎关注我的其它发布渠道