Files
STM32F4-Base/simulator/sim/sim_port.c
T

142 lines
4.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 模块名称:Simulator Display Port (SDL2 模拟器端口)
* 模块功能:为 PC 模拟器提供 LVGL SDL2 显示与键盘输入端口
* 适用平台:Windows / Linux / macOS (SDL2)
* 说明:替代 MCU 端的 ui_port.c,用于 PC 上 UI 开发与调试
*/
#include "sim_port.h"
#include "lvgl.h"
/* SDL 驱动头文件(由 lv_conf.h 中 LV_SDL_INCLUDE_PATH 指定) */
#define SDL_MAIN_HANDLED
#include <SDL.h>
/* 键盘输入设备句柄(全局,供 main.c SDL 事件循环读取) */
static lv_indev_t *g_kbd_indev = NULL;
/*
* 函数功能:初始化 SDL2 显示窗口与键盘输入设备
* 入口参数:hor_res - 水平分辨率 int32_t
* ver_res - 垂直分辨率 int32_t
* 返回值:0 - 成功,-1 - 失败
* 限定条件:lv_init() 已调用
* 函数说明:1. 创建 SDL 窗口显示设备
* 2. 创建键盘输入设备及默认输入组
* 3. 不创建鼠标/触摸设备(模拟器仅用键盘导航)
*/
int sim_port_init(int32_t hor_res, int32_t ver_res)
{
/* 创建默认输入组 */
lv_group_t *g = lv_group_create();
if (g == NULL) {
return -1;
}
lv_group_set_default(g);
/* 创建 SDL 窗口显示设备 */
lv_display_t *disp = lv_sdl_window_create(hor_res, ver_res);
if (disp == NULL) {
return -1;
}
lv_display_set_default(disp);
/* 初始化 mono 主题(1bpp 单色屏:白字黑底),并应用默认字体 */
#if LV_USE_THEME_MONO
lv_theme_t *th = lv_theme_mono_init(disp, true, LV_FONT_DEFAULT);
if (th != NULL) {
lv_display_set_theme(disp, th);
}
#endif
/* 创建键盘输入设备(方向键/确认/返回 → LVGL keypad) */
g_kbd_indev = lv_sdl_keyboard_create();
if (g_kbd_indev == NULL) {
return -1;
}
lv_indev_set_group(g_kbd_indev, lv_group_get_default());
lv_indev_set_display(g_kbd_indev, disp);
return 0;
}
/*
* 函数功能:获取 SDL 显示设备句柄
* 入口参数:无
* 返回值:显示设备指针 lv_display_t * 可能为 NULL
* 限定条件:sim_port_init() 已成功调用
*/
void *sim_port_get_display(void)
{
return (void *)lv_display_get_default();
}
/*
* 函数功能:读取当前屏幕内容并转换为 1bpp 单色位图(MSB-first)
* 入口参数:buf - 输出缓冲(调用方分配,≥ 宽*高/8 字节)
* buf_size - buf 容量(字节)
* 返回值:0 - 成功,-1 - 失败
* 限定条件:sim_port_init() 已成功;须在 SDL 所属线程(主循环线程)调用
* 函数说明:1. lv_sdl_window_get_renderer 取 SDL 渲染器
* 2. SDL_RenderReadPixels 读回屏幕实际呈现的 ARGB8888 像素
* 3. 按红通道阈值 128 判白(=1/墨)/黑(=0),逐行打包为 1bpp MSB-first
* 窗口模式为 I1+PARTIAL,LVGL 显示缓冲系分块且经 I1→ARGB8888
* 转换,直接读 get_buf_active 不可靠;读回屏幕呈现像素最稳,
* 且完全避开快照离屏重渲染(SDL 驱动下会卡派发循环)
*/
int sim_port_get_screen_mono(uint8_t *buf, uint32_t buf_size)
{
if (buf == NULL) {
return -1;
}
lv_display_t *disp = lv_display_get_default();
if (disp == NULL) {
return -1;
}
int32_t w = lv_display_get_horizontal_resolution(disp);
int32_t h = lv_display_get_vertical_resolution(disp);
if (w <= 0 || h <= 0) {
return -1;
}
uint32_t stride = (uint32_t)(w + 7) / 8u;
uint32_t need = stride * (uint32_t)h;
if (buf_size < need) {
return -1;
}
SDL_Renderer *renderer = (SDL_Renderer *)lv_sdl_window_get_renderer(disp);
if (renderer == NULL) {
return -1;
}
/* 读回屏幕实际呈现的像素(ARGB8888,4 字节/像素) */
uint32_t pitch = (uint32_t)w * 4u;
uint8_t *px = (uint8_t *)SDL_malloc((size_t)w * (size_t)h * 4u);
if (px == NULL) {
return -1;
}
int rc = SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_ARGB8888, px, (int)pitch);
if (rc != 0) {
SDL_free(px);
return -1;
}
/* 先清零(黑像素=0),ARGB8888 内存序 [B,G,R,A],红通道在偏移 2 */
lv_memset(buf, 0, need);
for (int32_t y = 0; y < h; y++) {
const uint8_t *row = px + (size_t)y * (size_t)pitch;
uint8_t *out = buf + (size_t)y * (size_t)stride;
for (int32_t x = 0; x < w; x++) {
if (row[(size_t)x * 4u + 2u] >= 128u) {
out[(uint32_t)x >> 3] |= (uint8_t)(0x80u >> (x & 7));
}
}
}
SDL_free(px);
return 0;
}