mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 18:26:48 +00:00
Patch refactor scm and textui (#289)
* 重构屏幕管理器和textui框架 * 切换字体为spleen,并增加对字体的抽象 * 修正文档 --------- Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
parent
5db5a5652c
commit
abe3a6ea3c
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -4,7 +4,6 @@
|
||||
"stdbool.h": "c",
|
||||
"printk.h": "c",
|
||||
"stdarg.h": "c",
|
||||
"font.h": "c",
|
||||
"trap.h": "c",
|
||||
"gate.h": "c",
|
||||
"process.h": "c",
|
||||
|
@ -29,6 +29,7 @@
|
||||
kernel/debug/index
|
||||
kernel/ktest/index
|
||||
kernel/cpu_arch/index
|
||||
kernel/libs/index
|
||||
|
||||
|
||||
.. toctree::
|
||||
|
12
docs/kernel/libs/index.rst
Normal file
12
docs/kernel/libs/index.rst
Normal file
@ -0,0 +1,12 @@
|
||||
====================================
|
||||
其他内核库
|
||||
====================================
|
||||
|
||||
这里的集中了内核中的一些库的文档,这些库不属于任何子系统。
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
lib_ui/scm
|
||||
lib_ui/textui
|
||||
|
83
docs/kernel/libs/lib_ui/scm.md
Normal file
83
docs/kernel/libs/lib_ui/scm.md
Normal file
@ -0,0 +1,83 @@
|
||||
# 屏幕管理器(SCM)
|
||||
|
||||
:::{note}
|
||||
作者: 周瀚杰 <2625553453@qq.com>
|
||||
:::
|
||||
  屏幕管理器用来管理控制所有ui框架,所有框架都必须先在屏幕管理器中注册才可使用,然后scm控制当前是哪个ui框架在使用
|
||||
|
||||
## traits
|
||||
|
||||
### ScmUiFramework
|
||||
  每个要注册到scm中的ui框架都必须实现这个trait中的方法,具体定义如下:
|
||||
```rust
|
||||
pub trait ScmUiFramework: Sync + Send + Debug {
|
||||
// 安装ui框架的回调函数
|
||||
fn install(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 卸载ui框架的回调函数
|
||||
fn uninstall(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 启用ui框架的回调函数
|
||||
fn enable(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 禁用ui框架的回调函数
|
||||
fn disable(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 改变ui框架的帧缓冲区的回调函数
|
||||
fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
/// @brief 获取ScmUiFramework的元数据
|
||||
/// @return 成功:Ok(ScmUiFramework的元数据)
|
||||
/// 失败:Err(错误码)
|
||||
fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
|
||||
// 若文件系统没有实现此方法,则返回“不支持”
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
}
|
||||
```
|
||||
## 主要API
|
||||
### scm_init() -初始化屏幕管理模块
|
||||
#### 原型
|
||||
```rust
|
||||
pub extern "C" fn scm_init()
|
||||
```
|
||||
#### 说明
|
||||
  scm_init()主要是初始化一些scm中使用的全局变量,例如是否使用双缓冲区标志位,textui未初始化时使用的一些全局变量
|
||||
|
||||
### scm_reinit() -当内存管理单元被初始化之后,重新初始化屏幕管理模块
|
||||
#### 原型
|
||||
```rust
|
||||
pub extern "C" fn scm_reinit() -> i32
|
||||
```
|
||||
#### 说明
|
||||
  scm_reinit()用于当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
||||
|
||||
### scm_enable_double_buffer() -允许双缓冲区
|
||||
#### 原型
|
||||
```rust
|
||||
pub extern "C" fn scm_enable_double_buffer() -> i32
|
||||
```
|
||||
#### 说明
|
||||
  scm_enable_double_buffer()用于启动双缓冲来往窗口输出打印信息。启用后,往窗口输出的信息会暂时放在一个缓冲区中,然后每次按一定时间将该缓冲区的信息输出到窗口帧缓冲区中,渲染显示到窗口上。
|
||||
|
||||
### scm_framework_enable() -启用某个ui框架,将它的帧缓冲区渲染到屏幕上
|
||||
#### 原型
|
||||
```rust
|
||||
pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError>
|
||||
```
|
||||
#### 说明
|
||||
  scm_framework_enable用于启用某个ui框架,将它的帧缓冲区渲染到屏幕上
|
||||
|
||||
|
||||
### scm_register() -向屏幕管理器注册UI框架
|
||||
#### 原型
|
||||
```rust
|
||||
pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError>
|
||||
```
|
||||
#### 说明
|
||||
  scm_register用于将ui框架注册到scm中,主要是调用ui框架的回调函数以安装ui框架,并将其激活
|
32
docs/kernel/libs/lib_ui/textui.md
Normal file
32
docs/kernel/libs/lib_ui/textui.md
Normal file
@ -0,0 +1,32 @@
|
||||
# 文本显示框架(textui)
|
||||
|
||||
:::{note}
|
||||
作者: 周瀚杰 <2625553453@qq.com>
|
||||
:::
|
||||
  文本框架主要用于DragonOS的文本的窗口渲染显示,往屏幕窗口中输出打印文本信息,往窗口显示文本分成两种情况:一种是当内存管理单元(mm)未被初始化时,不能进行动态内存分配,限制颇多(例如不能使用vec,mpsc等),所以直接往窗口的帧缓冲区输出打印信息,不使用虚拟行等复杂结构体;另一种是当内存管理单元(mm)已经初始化,可以进行动态内存分配,便可以使用一些复杂的结构体来处理要打印的文本信息。
|
||||
|
||||
|
||||
## 主要API
|
||||
### rs_textui_init() -textui框架初始化
|
||||
#### 原型
|
||||
```rust
|
||||
pub extern "C" fn rs_textui_init() -> i32
|
||||
```
|
||||
#### 说明
|
||||
  rs_textui_init()主要是初始化一些textui框架要使用到的一些全局变量信息(例如TEXTUIFRAMEWORK,TEXTUI_PRIVATE_INFO等),以及将textui框架注册到scm中。
|
||||
|
||||
### textui_putchar() -往textui框架中的当前使用的窗口打印文本信息
|
||||
#### 原型
|
||||
```rust
|
||||
pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32
|
||||
|
||||
pub fn textui_putchar(
|
||||
character: char,
|
||||
fr_color: FontColor,
|
||||
bk_color: FontColor,
|
||||
) -> Result<(), SystemError>
|
||||
```
|
||||
#### 说明
|
||||
  textui_putchar()要处理两种情况:一种是当内存管理单元(mm)未被初始化时,不能进行动态内存分配,限制颇多(例如不能使用vec,mpsc等),所以直接往窗口的帧缓冲区输出打印信息,不使用虚拟行等复杂结构体;另一种是当内存管理单元(mm)已经初始化,可以进行动态内存分配,便可以使用一些复杂的结构体来处理要打印的文本信息。
|
||||
|
||||
|
@ -7,10 +7,10 @@ use x86_64::registers::model_specific::EferFlags;
|
||||
|
||||
use crate::driver::uart::uart::c_uart_send_str;
|
||||
use crate::include::bindings::bindings::{
|
||||
disable_textui, enable_textui, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
||||
video_reinitialize,
|
||||
multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
||||
};
|
||||
use crate::libs::align::page_align_up;
|
||||
use crate::libs::lib_ui::screen_manager::scm_disable_put_to_window;
|
||||
use crate::libs::printk::PrintkWriter;
|
||||
use crate::libs::spinlock::SpinLock;
|
||||
|
||||
@ -315,8 +315,6 @@ pub fn mm_init() {
|
||||
unsafe { allocator_init() };
|
||||
// enable mmio
|
||||
mmio_init();
|
||||
// 启用printk的alloc选项
|
||||
PrintkWriter.enable_alloc();
|
||||
}
|
||||
|
||||
unsafe fn allocator_init() {
|
||||
@ -396,9 +394,8 @@ unsafe fn allocator_init() {
|
||||
unsafe { set_inner_allocator(buddy_allocator) };
|
||||
kinfo!("Successfully initialized buddy allocator");
|
||||
// 关闭显示输出
|
||||
unsafe {
|
||||
disable_textui();
|
||||
}
|
||||
scm_disable_put_to_window();
|
||||
|
||||
// make the new page table current
|
||||
{
|
||||
let mut binding = INNER_ALLOCATOR.lock();
|
||||
@ -416,16 +413,6 @@ unsafe fn allocator_init() {
|
||||
kdebug!("New page table enabled");
|
||||
}
|
||||
kdebug!("Successfully enabled new page table");
|
||||
// 重置显示输出目标
|
||||
unsafe {
|
||||
video_reinitialize(false);
|
||||
}
|
||||
|
||||
// 打开显示输出
|
||||
unsafe {
|
||||
enable_textui();
|
||||
}
|
||||
kdebug!("Text UI enabled");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -11,8 +11,8 @@
|
||||
#pragma once
|
||||
#include <arch/x86_64/include/asm/cmpxchg.h>
|
||||
|
||||
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
|
||||
#define atomic_set(atomic,val) (((atomic)->value) = (val)) // 设置原子变量的初始值
|
||||
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
|
||||
#define atomic_set(atomic, val) (((atomic)->value) = (val)) // 设置原子变量的初始值
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -1,316 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
unsigned char font_ascii[256][16]=
|
||||
{
|
||||
/* 0000 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0010 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0020 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0030 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x10,0x10,0x00,0x00}, //33 '!'
|
||||
{0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '"'
|
||||
{0x00,0x44,0x44,0x44,0xfe,0x44,0x44,0x44,0x44,0x44,0xfe,0x44,0x44,0x44,0x00,0x00}, // '#'
|
||||
{0x10,0x3a,0x56,0x92,0x92,0x90,0x50,0x38,0x14,0x12,0x92,0x92,0xd4,0xb8,0x10,0x10}, // '$'
|
||||
{0x62,0x92,0x94,0x94,0x68,0x08,0x10,0x10,0x20,0x2c,0x52,0x52,0x92,0x8c,0x00,0x00}, // '%'
|
||||
{0x00,0x70,0x88,0x88,0x88,0x90,0x60,0x47,0xa2,0x92,0x8a,0x84,0x46,0x39,0x00,0x00}, // '&'
|
||||
{0x04,0x08,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '''
|
||||
|
||||
/* 0040 */
|
||||
{0x02,0x04,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x04,0x02,0x00}, // '('
|
||||
{0x80,0x40,0x20,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x20,0x40,0x80,0x00}, // ')'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x10,0x92,0x54,0x38,0x54,0x92,0x10,0x00,0x00,0x00,0x00}, // '*'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x10,0x10,0x10,0xfe,0x10,0x10,0x10,0x00,0x00,0x00,0x00}, // '+'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x08,0x10}, // ','
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '-'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00}, // '.'
|
||||
{0x02,0x02,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x80}, // '/'
|
||||
{0x00,0x18,0x24,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x24,0x18,0x00,0x00}, //48 '0'
|
||||
{0x00,0x08,0x18,0x28,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x3e,0x00,0x00}, // '1'
|
||||
|
||||
/* 0050 */
|
||||
{0x00,0x18,0x24,0x42,0x42,0x02,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x7e,0x00,0x00}, // '2'
|
||||
{0x00,0x18,0x24,0x42,0x02,0x02,0x04,0x18,0x04,0x02,0x02,0x42,0x24,0x18,0x00,0x00}, // '3'
|
||||
{0x00,0x0c,0x0c,0x0c,0x14,0x14,0x14,0x24,0x24,0x44,0x7e,0x04,0x04,0x1e,0x00,0x00}, // '4'
|
||||
{0x00,0x7c,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x02,0x02,0x42,0x24,0x18,0x00,0x00}, // '5'
|
||||
{0x00,0x18,0x24,0x42,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00}, // '6'
|
||||
{0x00,0x7e,0x42,0x42,0x04,0x04,0x08,0x08,0x08,0x10,0x10,0x10,0x10,0x38,0x00,0x00}, // '7'
|
||||
{0x00,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x24,0x18,0x00,0x00}, // '8'
|
||||
{0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x26,0x1a,0x02,0x42,0x24,0x18,0x00,0x00}, // '9'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00}, //58 ':'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x08,0x10}, // ';'
|
||||
|
||||
/* 0060 */
|
||||
{0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00}, // '<'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00,0x00,0xfe,0x00,0x00,0x00,0x00,0x00,0x00}, // '='
|
||||
{0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00}, // '>'
|
||||
{0x00,0x38,0x44,0x82,0x82,0x82,0x04,0x08,0x10,0x10,0x00,0x00,0x18,0x18,0x00,0x00}, // '?'
|
||||
{0x00,0x38,0x44,0x82,0x9a,0xaa,0xaa,0xaa,0xaa,0xaa,0x9c,0x80,0x46,0x38,0x00,0x00}, // '@'
|
||||
{0x00,0x18,0x18,0x18,0x18,0x24,0x24,0x24,0x24,0x7e,0x42,0x42,0x42,0xe7,0x00,0x00}, //65 'A'
|
||||
{0x00,0xf0,0x48,0x44,0x44,0x44,0x48,0x78,0x44,0x42,0x42,0x42,0x44,0xf8,0x00,0x00}, // 'B'
|
||||
{0x00,0x3a,0x46,0x42,0x82,0x80,0x80,0x80,0x80,0x80,0x82,0x42,0x44,0x38,0x00,0x00}, // 'C'
|
||||
{0x00,0xf8,0x44,0x44,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x44,0x44,0xf8,0x00,0x00}, // 'D'
|
||||
{0x00,0xfe,0x42,0x42,0x40,0x40,0x44,0x7c,0x44,0x40,0x40,0x42,0x42,0xfe,0x00,0x00}, // 'E'
|
||||
|
||||
/* 0070 */
|
||||
{0x00,0xfe,0x42,0x42,0x40,0x40,0x44,0x7c,0x44,0x44,0x40,0x40,0x40,0xf0,0x00,0x00}, // 'F'
|
||||
{0x00,0x3a,0x46,0x42,0x82,0x80,0x80,0x9e,0x82,0x82,0x82,0x42,0x46,0x38,0x00,0x00}, // 'G'
|
||||
{0x00,0xe7,0x42,0x42,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x42,0xe7,0x00,0x00}, // 'H'
|
||||
{0x00,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'I'
|
||||
{0x00,0x1f,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x84,0x48,0x30,0x00}, // 'J'
|
||||
{0x00,0xe7,0x42,0x44,0x48,0x50,0x50,0x60,0x50,0x50,0x48,0x44,0x42,0xe7,0x00,0x00}, // 'K'
|
||||
{0x00,0xf0,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x42,0x42,0xfe,0x00,0x00}, // 'L'
|
||||
{0x00,0xc3,0x42,0x66,0x66,0x66,0x5a,0x5a,0x5a,0x42,0x42,0x42,0x42,0xe7,0x00,0x00}, // 'M'
|
||||
{0x00,0xc7,0x42,0x62,0x62,0x52,0x52,0x52,0x4a,0x4a,0x4a,0x46,0x46,0xe2,0x00,0x00}, // 'N'
|
||||
{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00}, // 'O'
|
||||
|
||||
/* 0080 */
|
||||
{0x00,0xf8,0x44,0x42,0x42,0x42,0x44,0x78,0x40,0x40,0x40,0x40,0x40,0xf0,0x00,0x00}, // 'P'
|
||||
{0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x82,0x82,0x92,0x8a,0x44,0x3a,0x00,0x00}, // 'Q'
|
||||
{0x00,0xfc,0x42,0x42,0x42,0x42,0x7c,0x44,0x42,0x42,0x42,0x42,0x42,0xe7,0x00,0x00}, // 'R'
|
||||
{0x00,0x3a,0x46,0x82,0x82,0x80,0x40,0x38,0x04,0x02,0x82,0x82,0xc4,0xb8,0x00,0x00}, // 'S'
|
||||
{0x00,0xfe,0x92,0x92,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'T'
|
||||
{0x00,0xe7,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x3c,0x00,0x00}, // 'U'
|
||||
{0x00,0xe7,0x42,0x42,0x42,0x42,0x24,0x24,0x24,0x24,0x18,0x18,0x18,0x18,0x00,0x00}, // 'V'
|
||||
{0x00,0xe7,0x42,0x42,0x42,0x5a,0x5a,0x5a,0x5a,0x24,0x24,0x24,0x24,0x24,0x00,0x00}, // 'W'
|
||||
{0x00,0xe7,0x42,0x42,0x24,0x24,0x24,0x18,0x24,0x24,0x24,0x42,0x42,0xe7,0x00,0x00}, // 'X'
|
||||
{0x00,0xee,0x44,0x44,0x44,0x28,0x28,0x28,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'Y'
|
||||
|
||||
/* 0090 */
|
||||
{0x00,0xfe,0x84,0x84,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x42,0x82,0xfe,0x00,0x00}, // 'Z'
|
||||
{0x00,0x3e,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,0x00}, //91 '['
|
||||
{0x80,0x80,0x40,0x40,0x20,0x20,0x20,0x10,0x10,0x08,0x08,0x04,0x04,0x04,0x02,0x02}, // '\'
|
||||
{0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x7c,0x00}, // ']'
|
||||
{0x00,0x10,0x28,0x44,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '^'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x00}, // '_'
|
||||
{0x10,0x08,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '`'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x70,0x08,0x04,0x3c,0x44,0x84,0x84,0x8c,0x76,0x00,0x00}, //97 'a'
|
||||
{0xc0,0x40,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x64,0x58,0x00,0x00}, // 'b'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x30,0x4c,0x84,0x84,0x80,0x80,0x82,0x44,0x38,0x00,0x00}, // 'c'
|
||||
|
||||
/* 0100 */
|
||||
{0x0c,0x04,0x04,0x04,0x04,0x34,0x4c,0x84,0x84,0x84,0x84,0x84,0x4c,0x36,0x00,0x00}, // 'd'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0xfc,0x80,0x82,0x42,0x3c,0x00,0x00}, // 'e'
|
||||
{0x0e,0x10,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7c,0x00,0x00}, // 'f'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x36,0x4c,0x84,0x84,0x84,0x84,0x4c,0x34,0x04,0x04,0x38}, // 'g'
|
||||
{0xc0,0x40,0x40,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x42,0x42,0x42,0xe3,0x00,0x00}, // 'h'
|
||||
{0x00,0x10,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00}, // 'i'
|
||||
{0x00,0x04,0x04,0x00,0x00,0x0c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x08,0x08,0x30}, // 'j'
|
||||
{0xc0,0x40,0x40,0x40,0x40,0x4e,0x44,0x48,0x50,0x60,0x50,0x48,0x44,0xe6,0x00,0x00}, // 'k'
|
||||
{0x30,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x38,0x00,0x00}, // 'l'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xf6,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0xdb,0x00,0x00}, // 'm'
|
||||
|
||||
/* 0110 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0xd8,0x64,0x42,0x42,0x42,0x42,0x42,0x42,0xe3,0x00,0x00}, // 'n'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x82,0x82,0x82,0x82,0x82,0x44,0x38,0x00,0x00}, // 'o'
|
||||
{0x00,0x00,0x00,0x00,0xd8,0x64,0x42,0x42,0x42,0x42,0x42,0x64,0x58,0x40,0x40,0xe0}, // 'p'
|
||||
{0x00,0x00,0x00,0x00,0x34,0x4c,0x84,0x84,0x84,0x84,0x84,0x4c,0x34,0x04,0x04,0x0e}, // 'q'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xdc,0x62,0x42,0x40,0x40,0x40,0x40,0x40,0xe0,0x00,0x00}, // 'r'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x7a,0x86,0x82,0xc0,0x38,0x06,0x82,0xc2,0xbc,0x00,0x00}, // 's'
|
||||
{0x00,0x00,0x10,0x10,0x10,0x7c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x0e,0x00,0x00}, // 't'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xc6,0x42,0x42,0x42,0x42,0x42,0x42,0x46,0x3b,0x00,0x00}, // 'u'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x00,0x00}, // 'v'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x5a,0x5a,0x5a,0x24,0x24,0x24,0x00,0x00}, // 'w'
|
||||
|
||||
/* 0120 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0xc6,0x44,0x28,0x28,0x10,0x28,0x28,0x44,0xc6,0x00,0x00}, // 'x'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xe7,0x42,0x42,0x24,0x24,0x24,0x18,0x18,0x10,0x10,0x60}, // 'y'
|
||||
{0x00,0x00,0x00,0x00,0x00,0xfe,0x82,0x84,0x08,0x10,0x20,0x42,0x82,0xfe,0x00,0x00}, // 'z'
|
||||
{0x00,0x06,0x08,0x10,0x10,0x10,0x10,0x60,0x10,0x10,0x10,0x10,0x08,0x06,0x00,0x00}, // '{'
|
||||
{0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10}, // '|'
|
||||
{0x00,0x60,0x10,0x08,0x08,0x08,0x08,0x06,0x08,0x08,0x08,0x08,0x10,0x60,0x00,0x00}, // '}'
|
||||
{0x00,0x72,0x8c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, // '~'
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0130 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
|
||||
/* 0140 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0150 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0160 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0170 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0180 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0190 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0200 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0210 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0220 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0230 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0240 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
/* 0250~0255 */
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||
|
||||
|
||||
};
|
||||
|
@ -16,29 +16,25 @@
|
||||
#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
|
||||
|
||||
// 字体颜色的宏定义
|
||||
#define WHITE 0x00ffffff //白
|
||||
#define BLACK 0x00000000 //黑
|
||||
#define RED 0x00ff0000 //红
|
||||
#define ORANGE 0x00ff8000 //橙
|
||||
#define YELLOW 0x00ffff00 //黄
|
||||
#define GREEN 0x0000ff00 //绿
|
||||
#define BLUE 0x000000ff //蓝
|
||||
#define INDIGO 0x0000ffff //靛
|
||||
#define PURPLE 0x008000ff //紫
|
||||
#define WHITE 0x00ffffff // 白
|
||||
#define BLACK 0x00000000 // 黑
|
||||
#define RED 0x00ff0000 // 红
|
||||
#define ORANGE 0x00ff8000 // 橙
|
||||
#define YELLOW 0x00ffff00 // 黄
|
||||
#define GREEN 0x0000ff00 // 绿
|
||||
#define BLUE 0x000000ff // 蓝
|
||||
#define INDIGO 0x0000ffff // 靛
|
||||
#define PURPLE 0x008000ff // 紫
|
||||
|
||||
// 异常的宏定义
|
||||
#define EPOS_OVERFLOW 1 // 坐标溢出
|
||||
#define EFB_MISMATCH 2 // 帧缓冲区与指定的屏幕大小不匹配
|
||||
#define EUNSUPPORTED 3 // 当前操作暂不被支持
|
||||
|
||||
#include "font.h"
|
||||
#include "glib.h"
|
||||
#include <libs/libUI/screen_manager.h>
|
||||
#include <libs/lib_ui/screen_manager.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大小) ps:位于font.h中
|
||||
|
||||
|
||||
/**
|
||||
* @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中
|
||||
*
|
||||
|
@ -326,7 +326,7 @@ void apic_local_apic_init()
|
||||
|
||||
// 检测是否成功启用xAPIC和x2APIC
|
||||
if ((eax & 0xc00) == 0xc00)
|
||||
kinfo("xAPIC & x2APIC enabled!");
|
||||
kinfo("xAPIC & x2APIC enabled!\n");
|
||||
else if ((eax & 0x800) == 0x800)
|
||||
kinfo("Only xAPIC enabled!");
|
||||
else
|
||||
|
@ -9,9 +9,11 @@ use crate::{
|
||||
devfs::{devfs_register, DevFS, DeviceINode},
|
||||
vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
|
||||
},
|
||||
include::bindings::bindings::{textui_putchar, BLACK, WHITE},
|
||||
kerror,
|
||||
libs::rwlock::RwLock,
|
||||
libs::{
|
||||
lib_ui::textui::{textui_putchar, FontColor},
|
||||
rwlock::RwLock,
|
||||
},
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
@ -255,10 +257,9 @@ impl IndexNode for TtyDevice {
|
||||
break;
|
||||
}
|
||||
// 输出到屏幕
|
||||
unsafe {
|
||||
for x in buf {
|
||||
textui_putchar(x as u16, WHITE, BLACK);
|
||||
}
|
||||
|
||||
for x in buf {
|
||||
textui_putchar(x as char, FontColor::WHITE, FontColor::BLACK).ok();
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
|
@ -17,10 +17,10 @@ extern void rs_register_softirq_video();
|
||||
|
||||
uint64_t video_refresh_expire_jiffies = 0;
|
||||
uint64_t video_last_refresh_pid = -1;
|
||||
|
||||
struct scm_buffer_info_t video_frame_buffer_info = {0};
|
||||
static struct multiboot_tag_framebuffer_info_t __fb_info;
|
||||
static struct scm_buffer_info_t *video_refresh_target = NULL;
|
||||
// static struct scm_buffer_info_t *_video_refresh_target = NULL;
|
||||
static struct scm_buffer_info_t video_refresh_target = {0};
|
||||
static struct process_control_block *video_daemon_pcb = NULL;
|
||||
static spinlock_t daemon_refresh_lock;
|
||||
|
||||
@ -35,9 +35,9 @@ void init_frame_buffer()
|
||||
kinfo("Re-mapping VBE frame buffer...");
|
||||
|
||||
video_frame_buffer_info.vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET;
|
||||
|
||||
rs_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
|
||||
|
||||
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
|
||||
kinfo("VBE frame buffer successfully Re-mapped!");
|
||||
}
|
||||
|
||||
@ -56,12 +56,16 @@ int video_refresh_daemon(void *unused)
|
||||
if (rs_clock() >= video_refresh_expire_jiffies)
|
||||
{
|
||||
|
||||
if (likely(video_refresh_target != NULL))
|
||||
if (likely(video_refresh_target.size != 0))
|
||||
{
|
||||
spin_lock(&daemon_refresh_lock);
|
||||
if (video_frame_buffer_info.vaddr != NULL)
|
||||
memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr,
|
||||
video_refresh_target->size);
|
||||
{
|
||||
// kdebug("video_frame_buffer_info.vaddr = %#018lx,get_video_refresh_target_vaddr()= %#018lx" ,video_frame_buffer_info.vaddr,get_video_refresh_target_vaddr());
|
||||
|
||||
memcpy((void *)video_frame_buffer_info.vaddr, (void *)get_video_refresh_target_vaddr(),
|
||||
video_refresh_target.size);
|
||||
}
|
||||
spin_unlock(&daemon_refresh_lock);
|
||||
video_daemon_pcb->virtual_runtime =
|
||||
0xfffff0000000; // 临时解决由于显示刷新进程的虚拟运行时间过大/过小,导致其不运行,或者一直运行的问题。将来应使用实时调度解决它
|
||||
@ -76,6 +80,10 @@ int video_refresh_daemon(void *unused)
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t get_video_refresh_target_vaddr()
|
||||
{
|
||||
return video_refresh_target.vaddr;
|
||||
}
|
||||
/**
|
||||
* @brief 唤醒video的守护进程
|
||||
*/
|
||||
@ -105,10 +113,13 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
|
||||
{
|
||||
rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
|
||||
// 计算开始时间
|
||||
video_refresh_expire_jiffies = rs_timer_next_n_ms_jiffies(10 * REFRESH_INTERVAL);
|
||||
video_refresh_expire_jiffies = rs_timer_next_n_ms_jiffies(50 * REFRESH_INTERVAL);
|
||||
kdebug("video_frame_buffer_info.vaddr = %#018lx,get_video_refresh_target_vaddr()= %#018lx", video_frame_buffer_info.vaddr, get_video_refresh_target_vaddr());
|
||||
|
||||
io_mfence();
|
||||
// 创建video守护进程
|
||||
video_daemon_pcb = kthread_run(&video_refresh_daemon, NULL, "Video refresh daemon");
|
||||
io_mfence();
|
||||
video_daemon_pcb->virtual_runtime = 0; // 特殊情况, 最高优先级, 以后再改
|
||||
// 启用屏幕刷新软中断
|
||||
rs_register_softirq_video();
|
||||
@ -123,7 +134,8 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
|
||||
* @param buf
|
||||
* @return int
|
||||
*/
|
||||
int video_set_refresh_target(struct scm_buffer_info_t *buf)
|
||||
|
||||
int video_set_refresh_target(struct scm_buffer_info_t buf)
|
||||
{
|
||||
|
||||
rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
|
||||
@ -137,10 +149,11 @@ int video_set_refresh_target(struct scm_buffer_info_t *buf)
|
||||
// rs_usleep(1000);
|
||||
// }
|
||||
// kdebug("buf = %#018lx", buf);
|
||||
|
||||
video_refresh_target = buf;
|
||||
|
||||
rs_register_softirq_video();
|
||||
kdebug("register softirq video done");
|
||||
// rs_raise_softirq(VIDEO_REFRESH_SIRQ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -153,8 +166,8 @@ int video_init()
|
||||
|
||||
memset(&video_frame_buffer_info, 0, sizeof(struct scm_buffer_info_t));
|
||||
memset(&__fb_info, 0, sizeof(struct multiboot_tag_framebuffer_info_t));
|
||||
video_refresh_target = NULL;
|
||||
|
||||
// _video_refresh_target = NULL;
|
||||
video_refresh_target = (struct scm_buffer_info_t){0};
|
||||
io_mfence();
|
||||
// 从multiboot2获取帧缓冲区信息
|
||||
int reserved;
|
||||
@ -180,17 +193,21 @@ int video_init()
|
||||
|
||||
video_frame_buffer_info.size =
|
||||
video_frame_buffer_info.width * video_frame_buffer_info.height * ((video_frame_buffer_info.bit_depth + 7) / 8);
|
||||
// 先临时映射到该地址,稍后再重新映射
|
||||
video_frame_buffer_info.vaddr = 0xffff800003000000;
|
||||
// 先临时映射到50M的位置,稍后再重新映射
|
||||
video_frame_buffer_info.vaddr = 0xffff800003200000;
|
||||
|
||||
char init_text1[] = "Video driver to map.\n";
|
||||
for (int i = 0; i < sizeof(init_text1) - 1; ++i)
|
||||
c_uart_send(COM1, init_text1[i]);
|
||||
|
||||
rs_pseudo_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size);
|
||||
|
||||
io_mfence();
|
||||
char init_text2[] = "Video driver initialized.\n";
|
||||
for (int i = 0; i < sizeof(init_text2) - 1; ++i)
|
||||
{
|
||||
c_uart_send(COM1, init_text2[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
#include <stdbool.h>
|
||||
#include <libs/libUI/screen_manager.h>
|
||||
|
||||
#include <libs/lib_ui/screen_manager.h>
|
||||
extern struct scm_buffer_info_t video_frame_buffer_info;
|
||||
/**
|
||||
* @brief 重新初始化显示驱动,需先低级初始化才能高级初始化
|
||||
* @param level 初始化等级
|
||||
@ -21,13 +21,15 @@ int video_init();
|
||||
|
||||
/**
|
||||
* @brief 设置帧缓冲区刷新目标
|
||||
*
|
||||
* @param buf
|
||||
* @return int
|
||||
*
|
||||
* @param buf
|
||||
* @return int
|
||||
*/
|
||||
int video_set_refresh_target(struct scm_buffer_info_t *buf);
|
||||
// int video_set_refresh_target(struct scm_buffer_info_t *buf);
|
||||
int video_set_refresh_target(struct scm_buffer_info_t buf);
|
||||
|
||||
extern uint64_t video_refresh_expire_jiffies;
|
||||
extern uint64_t video_last_refresh_pid;
|
||||
|
||||
void video_refresh_framebuffer(void *data);
|
||||
void video_refresh_framebuffer(void *data);
|
||||
uint64_t get_video_refresh_target_vaddr();
|
@ -287,8 +287,8 @@ ENTRY(_start64)
|
||||
loop .fill_pde_64
|
||||
|
||||
// 最低级
|
||||
// 循环 512*50=25600 次,填满50页
|
||||
mov $25600, %ecx
|
||||
// 循环 512*25=12800 次,填满25页,共50M
|
||||
mov $12800, %ecx
|
||||
mov $__PT_S, %eax
|
||||
mov $0x3, %ebx
|
||||
.fill_pt_64:
|
||||
@ -297,6 +297,14 @@ ENTRY(_start64)
|
||||
add $8, %eax
|
||||
loop .fill_pt_64
|
||||
|
||||
// 50-100M填0,共25个页表
|
||||
mov $12800, %ecx
|
||||
.fill_pt_64_2:
|
||||
mov $0, 0(%eax)
|
||||
add $8, %eax
|
||||
loop .fill_pt_64_2
|
||||
|
||||
|
||||
|
||||
// ==== 加载CR3寄存器
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include <exception/gate.h>
|
||||
#include <include/DragonOS/refcount.h>
|
||||
#include <include/DragonOS/signal.h>
|
||||
#include <libs/libUI/textui.h>
|
||||
#include <libs/lib_ui/textui.h>
|
||||
#include <mm/mm-types.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/mmio.h>
|
||||
|
@ -54,16 +54,16 @@ extern crate thingbuf;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
extern crate x86;
|
||||
|
||||
use crate::libs::lib_ui::textui::FontColor;
|
||||
use crate::mm::allocator::kernel_allocator::KernelAllocator;
|
||||
|
||||
// <3>
|
||||
use crate::{
|
||||
arch::asm::current::current_pcb,
|
||||
include::bindings::bindings::{process_do_exit, BLACK, GREEN},
|
||||
arch::asm::current::current_pcb, include::bindings::bindings::process_do_exit,
|
||||
net::net_core::net_init,
|
||||
};
|
||||
|
||||
// 声明全局的slab分配器
|
||||
// 声明全局的分配器
|
||||
#[cfg_attr(not(test), global_allocator)]
|
||||
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
|
||||
|
||||
@ -106,7 +106,7 @@ pub fn panic(info: &PanicInfo) -> ! {
|
||||
/// 该函数用作测试,在process.c的initial_kernel_thread()中调用了此函数
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __rust_demo_func() -> i32 {
|
||||
printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
|
||||
printk_color!(FontColor::GREEN, FontColor::BLACK, "__rust_demo_func()\n");
|
||||
let r = net_init();
|
||||
if r.is_err() {
|
||||
kwarn!("net_init() failed: {:?}", r.err().unwrap());
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
kernel_lib_subdirs:= libUI sys
|
||||
kernel_lib_subdirs:= sys
|
||||
|
||||
kernel_lib_objs:= $(shell find ./*.c)
|
||||
|
||||
|
@ -1,13 +0,0 @@
|
||||
|
||||
all: screen_manager.o textui.o textui-render.o
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
screen_manager.o: screen_manager.c
|
||||
$(CC) $(CFLAGS) -c screen_manager.c -o screen_manager.o
|
||||
|
||||
textui.o: textui.c
|
||||
$(CC) $(CFLAGS) -c textui.c -o textui.o
|
||||
|
||||
textui-render.o: textui-render.c
|
||||
$(CC) $(CFLAGS) -c textui-render.c -o textui-render.o
|
@ -1,351 +0,0 @@
|
||||
#include "screen_manager.h"
|
||||
#include <common/kprint.h>
|
||||
#include <common/spinlock.h>
|
||||
#include <common/string.h>
|
||||
#include <driver/multiboot2/multiboot2.h>
|
||||
#include <driver/uart/uart.h>
|
||||
#include <driver/video/video.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/slab.h>
|
||||
|
||||
extern struct scm_buffer_info_t video_frame_buffer_info;
|
||||
static struct List scm_framework_list;
|
||||
static spinlock_t scm_register_lock; // 框架注册锁
|
||||
static spinlock_t scm_screen_own_lock = {1}; // 改变屏幕归属者时,需要对该锁加锁
|
||||
static struct scm_ui_framework_t *__current_framework; // 当前拥有屏幕控制权的框架
|
||||
static uint32_t scm_ui_max_id = 0;
|
||||
static bool __scm_alloc_enabled = false; // 允许动态申请内存的标志位
|
||||
static bool __scm_double_buffer_enabled = false; // 允许双缓冲的标志位
|
||||
|
||||
/**
|
||||
* @brief 创建新的帧缓冲区
|
||||
*
|
||||
* @param type 帧缓冲区类型
|
||||
* @return struct scm_buffer_info_t* 新的帧缓冲区结构体
|
||||
*/
|
||||
static struct scm_buffer_info_t *__create_buffer(uint64_t type)
|
||||
{
|
||||
// 若未启用双缓冲,则直接返回帧缓冲区
|
||||
if (unlikely(__scm_double_buffer_enabled == false))
|
||||
return &video_frame_buffer_info;
|
||||
|
||||
struct scm_buffer_info_t *buf = (struct scm_buffer_info_t *)kmalloc(sizeof(struct scm_buffer_info_t), 0);
|
||||
if (buf == NULL)
|
||||
return (void *)-ENOMEM;
|
||||
memset(buf, 0, sizeof(struct scm_buffer_info_t));
|
||||
buf->bit_depth = video_frame_buffer_info.bit_depth;
|
||||
buf->flags = SCM_BF_DB;
|
||||
|
||||
if (type & SCM_BF_PIXEL)
|
||||
buf->flags |= SCM_BF_PIXEL;
|
||||
else
|
||||
buf->flags |= SCM_BF_TEXT;
|
||||
buf->height = video_frame_buffer_info.height;
|
||||
buf->width = video_frame_buffer_info.width;
|
||||
buf->size = video_frame_buffer_info.size;
|
||||
|
||||
void* buf_vaddr = kzalloc(video_frame_buffer_info.size, 0);
|
||||
if (buf_vaddr == NULL)
|
||||
goto failed;
|
||||
buf->vaddr = buf_vaddr;
|
||||
return buf;
|
||||
failed:;
|
||||
kfree(buf);
|
||||
return (void *)-ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 销毁双缓冲区
|
||||
*
|
||||
* @param buf
|
||||
* @return int
|
||||
*/
|
||||
static int __destroy_buffer(struct scm_buffer_info_t *buf)
|
||||
{
|
||||
// 不能销毁帧缓冲区对象
|
||||
if (unlikely(buf == &video_frame_buffer_info || buf == NULL))
|
||||
return -EINVAL;
|
||||
if (unlikely(buf->vaddr == NULL))
|
||||
return -EINVAL;
|
||||
if (unlikely(verify_area(buf->vaddr, buf->size) == true))
|
||||
return -EINVAL;
|
||||
// 是否双缓冲区
|
||||
if (buf->flags & SCM_BF_FB)
|
||||
return -EINVAL;
|
||||
|
||||
// 释放内存页
|
||||
kfree((void*)buf->vaddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化屏幕管理模块
|
||||
*
|
||||
*/
|
||||
void scm_init()
|
||||
{
|
||||
list_init(&scm_framework_list);
|
||||
spin_init(&scm_register_lock);
|
||||
spin_init(&scm_screen_own_lock);
|
||||
io_mfence();
|
||||
scm_ui_max_id = 0;
|
||||
__scm_alloc_enabled = false; // 禁用动态申请内存
|
||||
__scm_double_buffer_enabled = false; // 禁用双缓冲
|
||||
__current_framework = NULL;
|
||||
}
|
||||
/**
|
||||
* @brief 检查ui框架结构体中的参数设置是否合法
|
||||
*
|
||||
* @param name 框架名称
|
||||
* @param type 框架类型
|
||||
* @param ops 框架的操作
|
||||
* @return int
|
||||
*/
|
||||
static int __check_ui_param(const char *name, const uint8_t type, const struct scm_ui_framework_operations_t *ops)
|
||||
{
|
||||
if (name == NULL)
|
||||
return -EINVAL;
|
||||
if ((type == SCM_FRAMWORK_TYPE_GUI || type == SCM_FRAMWORK_TYPE_TEXT) == 0)
|
||||
return -EINVAL;
|
||||
if (ops == NULL)
|
||||
return -EINVAL;
|
||||
if (ops->install == NULL || ops->uninstall == NULL || ops->enable == NULL || ops->disable == NULL ||
|
||||
ops->change == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief 向屏幕管理器注册UI框架(动态获取框架对象结构体)
|
||||
*
|
||||
* @param name 框架名
|
||||
* @param type 类型
|
||||
* @param ops 框架操作方法
|
||||
* @return int
|
||||
*/
|
||||
int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops)
|
||||
{
|
||||
// 若未启用动态申请,则返回。
|
||||
if (unlikely(__scm_alloc_enabled == false))
|
||||
return -EAGAIN;
|
||||
|
||||
// 检查参数合法性
|
||||
if (__check_ui_param(name, type, ops) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
struct scm_ui_framework_t *ui = (struct scm_ui_framework_t *)kmalloc(sizeof(struct scm_ui_framework_t *), 0);
|
||||
memset(ui, 0, sizeof(struct scm_ui_framework_t));
|
||||
strncpy(ui->name, name, 15);
|
||||
ui->type = type;
|
||||
ui->ui_ops = ops;
|
||||
list_init(&ui->list);
|
||||
|
||||
spin_lock(&scm_register_lock);
|
||||
ui->id = scm_ui_max_id++;
|
||||
spin_unlock(&scm_register_lock);
|
||||
|
||||
// 创建帧缓冲区
|
||||
ui->buf = __create_buffer(ui->type);
|
||||
if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
|
||||
{
|
||||
kfree(ui);
|
||||
return -ENOMEM;
|
||||
}
|
||||
// 把ui框架加入链表
|
||||
list_add(&scm_framework_list, &ui->list);
|
||||
|
||||
// 调用ui框架的回调函数以安装ui框架,并将其激活
|
||||
ui->ui_ops->install(ui->buf);
|
||||
ui->ui_ops->enable(NULL);
|
||||
if (__current_framework == NULL)
|
||||
return scm_framework_enable(ui);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器注册UI框架(静态设置的框架对象)
|
||||
*
|
||||
* @param ui 框架结构体指针
|
||||
* @return int 错误码
|
||||
*/
|
||||
int scm_register(struct scm_ui_framework_t *ui)
|
||||
{
|
||||
if (ui == NULL)
|
||||
return -EINVAL;
|
||||
if (__check_ui_param(ui->name, ui->type, ui->ui_ops) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
list_init(&ui->list);
|
||||
spin_lock(&scm_register_lock);
|
||||
ui->id = scm_ui_max_id++;
|
||||
spin_unlock(&scm_register_lock);
|
||||
|
||||
ui->buf = __create_buffer(ui->type);
|
||||
|
||||
if ((uint64_t)(ui->buf) == (uint64_t)-ENOMEM)
|
||||
return -ENOMEM;
|
||||
|
||||
// 把ui框架加入链表
|
||||
list_add(&scm_framework_list, &ui->list);
|
||||
|
||||
// 调用ui框架的回调函数以安装ui框架,并将其激活
|
||||
ui->ui_ops->install(ui->buf);
|
||||
ui->ui_ops->enable(NULL);
|
||||
|
||||
if (__current_framework == NULL)
|
||||
return scm_framework_enable(ui);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器卸载UI框架
|
||||
*
|
||||
* @param ui ui框架结构体
|
||||
* @return int
|
||||
*/
|
||||
int scm_unregister(struct scm_ui_framework_t *ui)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器卸载动态创建的UI框架
|
||||
*
|
||||
* @param ui ui框架结构体
|
||||
* @return int
|
||||
*/
|
||||
int scm_unregister_alloc(struct scm_ui_framework_t *ui)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 允许动态申请内存
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int scm_enable_alloc()
|
||||
{
|
||||
__scm_alloc_enabled = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 允许双缓冲区
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int scm_enable_double_buffer()
|
||||
{
|
||||
if (__scm_double_buffer_enabled == true) // 已经开启了双缓冲区了, 直接退出
|
||||
return 0;
|
||||
__scm_double_buffer_enabled = true;
|
||||
if (list_empty(&scm_framework_list)) // scm 框架链表为空
|
||||
return 0;
|
||||
|
||||
// 逐个检查已经注册了的ui框架,将其缓冲区更改为双缓冲
|
||||
struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
|
||||
// 这里的ptr不需要特判空指针吗 问题1
|
||||
do
|
||||
{
|
||||
if (ptr->buf == &video_frame_buffer_info)
|
||||
{
|
||||
c_uart_send_str(COM1, "##init double buffer##\n");
|
||||
struct scm_buffer_info_t *buf = __create_buffer(SCM_BF_DB | SCM_BF_PIXEL);
|
||||
if ((uint64_t)(buf) == (uint64_t)-ENOMEM)
|
||||
return -ENOMEM;
|
||||
c_uart_send_str(COM1, "##to change double buffer##\n");
|
||||
|
||||
if (ptr->ui_ops->change(buf) != 0) // 这里的change回调函数不会是空指针吗 问题2
|
||||
{
|
||||
|
||||
__destroy_buffer(buf);
|
||||
kfree(buf);
|
||||
}
|
||||
}
|
||||
|
||||
} while (list_next(&ptr->list) != &scm_framework_list); // 枚举链表的每一个ui框架
|
||||
|
||||
// 设置定时刷新的对象
|
||||
video_set_refresh_target(__current_framework->buf);
|
||||
// 通知显示驱动,启动双缓冲
|
||||
video_reinitialize(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
|
||||
*
|
||||
* @param ui 要启动的ui框架
|
||||
* @return int 返回码
|
||||
*/
|
||||
int scm_framework_enable(struct scm_ui_framework_t *ui)
|
||||
{
|
||||
if (ui->buf->vaddr == NULL)
|
||||
return -EINVAL;
|
||||
spin_lock(&scm_screen_own_lock);
|
||||
int retval = 0;
|
||||
if (__scm_double_buffer_enabled == true)
|
||||
{
|
||||
|
||||
retval = video_set_refresh_target(ui->buf);
|
||||
if (retval == 0)
|
||||
__current_framework = ui;
|
||||
}
|
||||
else
|
||||
__current_framework = ui;
|
||||
ui->ui_ops->enable(NULL);
|
||||
spin_unlock(&scm_screen_own_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 禁用某个ui框架,将它的帧缓冲区从屏幕上移除
|
||||
*
|
||||
* @param ui 要禁用的ui框架
|
||||
* @return int 返回码
|
||||
*/
|
||||
int scm_framework_disable(struct scm_ui_framework_t *ui)
|
||||
{
|
||||
if (ui->buf->vaddr == NULL)
|
||||
return -EINVAL;
|
||||
spin_lock(&scm_screen_own_lock);
|
||||
if (ui != __current_framework)
|
||||
return -EINVAL;
|
||||
int retval = 0;
|
||||
if (__scm_double_buffer_enabled == true)
|
||||
{
|
||||
retval = video_set_refresh_target(NULL);
|
||||
if (retval == 0)
|
||||
__current_framework = NULL;
|
||||
}
|
||||
else
|
||||
__current_framework = NULL;
|
||||
|
||||
ui->ui_ops->disable(NULL);
|
||||
spin_unlock(&scm_screen_own_lock);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
||||
*
|
||||
*/
|
||||
void scm_reinit()
|
||||
{
|
||||
scm_enable_alloc();
|
||||
// video_reinitialize(false);
|
||||
|
||||
// 遍历当前所有使用帧缓冲区的框架,更新地址
|
||||
// 逐个检查已经注册了的ui框架,将其缓冲区更改为双缓冲
|
||||
struct scm_ui_framework_t *ptr = container_of(list_next(&scm_framework_list), struct scm_ui_framework_t, list);
|
||||
do
|
||||
{
|
||||
if (ptr->buf == &video_frame_buffer_info)
|
||||
{
|
||||
ptr->ui_ops->change(&video_frame_buffer_info);
|
||||
}
|
||||
} while (list_next(&ptr->list) != &scm_framework_list);
|
||||
return;
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
#pragma once
|
||||
#include <common/sys/types.h>
|
||||
#include <common/glib.h>
|
||||
|
||||
// 帧缓冲区标志位
|
||||
#define SCM_BF_FB (1 << 0) // 当前buffer是设备显存中的帧缓冲区
|
||||
#define SCM_BF_DB (1 << 1) // 当前buffer是双缓冲
|
||||
#define SCM_BF_TEXT (1 << 2) // 使用文本模式
|
||||
#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
|
||||
|
||||
// ui框架类型
|
||||
#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
|
||||
#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
|
||||
|
||||
/**
|
||||
* @brief 帧缓冲区信息结构体
|
||||
*
|
||||
*/
|
||||
struct scm_buffer_info_t
|
||||
{
|
||||
uint32_t width; // 帧缓冲区宽度(pixel或columns)
|
||||
uint32_t height; // 帧缓冲区高度(pixel或lines)
|
||||
uint32_t size; // 帧缓冲区大小(bytes)
|
||||
uint32_t bit_depth; // 像素点位深度
|
||||
|
||||
uint64_t vaddr; // 帧缓冲区的地址
|
||||
uint64_t flags; // 帧缓冲区标志位
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 上层ui框架应当实现的接口
|
||||
*
|
||||
*/
|
||||
struct scm_ui_framework_operations_t
|
||||
{
|
||||
int (*install)(struct scm_buffer_info_t *buf); // 安装ui框架的回调函数
|
||||
int (*uninstall)(void *args); // 卸载ui框架的回调函数
|
||||
int (*enable)(void *args); // 启用ui框架的回调函数
|
||||
int (*disable)(void *args); // 禁用ui框架的回调函数
|
||||
int (*change)(struct scm_buffer_info_t *buf); // 改变ui框架的帧缓冲区的回调函数
|
||||
};
|
||||
struct scm_ui_framework_t
|
||||
{
|
||||
struct List list;
|
||||
uint16_t id;
|
||||
char name[16];
|
||||
uint8_t type;
|
||||
struct scm_ui_framework_operations_t *ui_ops;
|
||||
struct scm_buffer_info_t *buf;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化屏幕管理模块
|
||||
*
|
||||
*/
|
||||
void scm_init();
|
||||
|
||||
/**
|
||||
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
||||
*
|
||||
*/
|
||||
void scm_reinit();
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器注册UI框架(动态获取框架对象结构体)
|
||||
*
|
||||
* @param name 框架名
|
||||
* @param type 类型
|
||||
* @param ops 框架操作方法
|
||||
* @return int
|
||||
*/
|
||||
int scm_register_alloc(const char *name, const uint8_t type, struct scm_ui_framework_operations_t *ops);
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器注册UI框架(静态设置的框架对象)
|
||||
*
|
||||
* @param ui 框架结构体指针
|
||||
* @return int 错误码
|
||||
*/
|
||||
int scm_register(struct scm_ui_framework_t *ui);
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器卸载UI框架
|
||||
*
|
||||
* @param ui ui框架结构体
|
||||
* @return int
|
||||
*/
|
||||
int scm_unregister(struct scm_ui_framework_t *ui);
|
||||
|
||||
/**
|
||||
* @brief 向屏幕管理器卸载动态创建的UI框架
|
||||
*
|
||||
* @param ui ui框架结构体
|
||||
* @return int
|
||||
*/
|
||||
int scm_unregister_alloc(struct scm_ui_framework_t *ui);
|
||||
|
||||
/**
|
||||
* @brief 允许动态申请内存
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int scm_enable_alloc();
|
||||
|
||||
/**
|
||||
* @brief 允许双缓冲区
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int scm_enable_double_buffer();
|
||||
|
||||
/**
|
||||
* @brief 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
|
||||
*
|
||||
* @param ui 要启动的ui框架
|
||||
* @return int 返回码
|
||||
*/
|
||||
int scm_framework_enable(struct scm_ui_framework_t *ui);
|
||||
|
||||
int scm_framework_disable(struct scm_ui_framework_t *ui);
|
@ -1,154 +0,0 @@
|
||||
#include "textui.h"
|
||||
#include <driver/uart/uart.h>
|
||||
#include <common/errno.h>
|
||||
#include "screen_manager.h"
|
||||
|
||||
#define WHITE 0x00ffffff //白
|
||||
#define BLACK 0x00000000 //黑
|
||||
#define RED 0x00ff0000 //红
|
||||
#define ORANGE 0x00ff8000 //橙
|
||||
#define YELLOW 0x00ffff00 //黄
|
||||
#define GREEN 0x0000ff00 //绿
|
||||
#define BLUE 0x000000ff //蓝
|
||||
#define INDIGO 0x0000ffff //靛
|
||||
#define PURPLE 0x008000ff //紫
|
||||
|
||||
// 根据rgb计算出最终的颜色值
|
||||
#define calculate_color(r, g, b) ((((r & 0xff) << 16) | ((g & 0xff) << 8) | (b & 0xff)) & 0x00ffffff)
|
||||
|
||||
extern struct scm_ui_framework_t textui_framework;
|
||||
|
||||
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大小) ps:位于font.h中
|
||||
static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character);
|
||||
|
||||
/**
|
||||
* @brief 重新渲染整个虚拟行
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id)
|
||||
{
|
||||
if (textui_is_chromatic(window->flags))
|
||||
return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
|
||||
else
|
||||
return textui_refresh_characters(window, vline_id, 0, window->chars_per_line);
|
||||
}
|
||||
|
||||
int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count)
|
||||
{
|
||||
char bufff[16] = {0};
|
||||
// uart_send_str(COM1, " BEGIN ");
|
||||
for (int i = start; i < window->vlines_num && count > 0; ++i, --count)
|
||||
{
|
||||
// sprintk(bufff, "[ 1fresh: %d ] ", i);
|
||||
// uart_send_str(COM1, bufff);
|
||||
textui_refresh_vline(window, i);
|
||||
}
|
||||
start = 0;
|
||||
while (count > 0)
|
||||
{
|
||||
// sprintk(bufff, "[ 2fresh: %d ] ", start);
|
||||
// uart_send_str(COM1, bufff);
|
||||
// sprintk(bufff, " index=%d ", (window->vlines.chromatic)[start].index);
|
||||
// uart_send_str(COM1, bufff);
|
||||
textui_refresh_vline(window, start);
|
||||
++start;
|
||||
--count;
|
||||
}
|
||||
// uart_send_str(COM1, " END ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 刷新某个虚拟行的连续n个字符对象
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @param start 起始字符号
|
||||
* @param count 要刷新的字符数量
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count)
|
||||
{
|
||||
if (window->id != __textui_get_current_window_id())
|
||||
return 0;
|
||||
// 判断虚拟行参数是否合法
|
||||
if (unlikely(vline_id >= window->vlines_num && (start + count) > window->chars_per_line))
|
||||
return -EINVAL;
|
||||
|
||||
// 计算虚拟行对应的真实行
|
||||
int actual_line_id = (int)vline_id - window->top_vline;
|
||||
if (actual_line_id < 0)
|
||||
actual_line_id += __textui_get_actual_lines();
|
||||
// 判断真实行id是否合理
|
||||
if (unlikely(actual_line_id < 0 || actual_line_id >= __textui_get_actual_lines()))
|
||||
return 0;
|
||||
|
||||
// 若是彩色像素模式
|
||||
if (textui_is_chromatic(window->flags))
|
||||
{
|
||||
struct textui_vline_chromatic_t *vline = &(window->vlines.chromatic)[vline_id];
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
|
||||
__textui_render_chromatic(actual_line_id, start + i, &vline->chars[start + i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 渲染彩色字符
|
||||
*
|
||||
* @param actual_line 真实行的行号
|
||||
* @param index 列号
|
||||
* @param character 要渲染的字符
|
||||
*/
|
||||
static void __textui_render_chromatic(uint16_t actual_line, uint16_t index, struct textui_char_chromatic_t *character)
|
||||
{
|
||||
/**
|
||||
* @brief 在屏幕上指定位置打印字符
|
||||
*
|
||||
* @param x 左上角列像素点位置
|
||||
* @param y 左上角行像素点位置
|
||||
* @param FRcolor 字体颜色
|
||||
* @param BKcolor 背景颜色
|
||||
* @param font 字符的bitmap
|
||||
*/
|
||||
|
||||
unsigned char *font_ptr = font_ascii[(uint8_t)character->c];
|
||||
unsigned int *addr;
|
||||
uint32_t *fb = (uint32_t *)textui_framework.buf->vaddr;
|
||||
|
||||
uint32_t FRcolor = character->FRcolor & 0x00ffffff;
|
||||
|
||||
uint32_t BKcolor = character->BKcolor & 0x00ffffff;
|
||||
|
||||
uint32_t x = index * TEXTUI_CHAR_WIDTH;
|
||||
uint32_t y = actual_line * TEXTUI_CHAR_HEIGHT;
|
||||
|
||||
int testbit; // 用来测试某位是背景还是字体本身
|
||||
|
||||
for (int i = 0; i < TEXTUI_CHAR_HEIGHT; ++i)
|
||||
{
|
||||
// 计算出帧缓冲区的地址
|
||||
addr = (uint32_t *)(fb + textui_framework.buf->width * (y + i) + x);
|
||||
|
||||
testbit = (1 << (TEXTUI_CHAR_WIDTH + 1));
|
||||
for (int j = 0; j < TEXTUI_CHAR_WIDTH; ++j)
|
||||
{
|
||||
// 从左往右逐个测试相应位
|
||||
testbit >>= 1;
|
||||
if (*font_ptr & testbit)
|
||||
*addr = FRcolor; // 字,显示前景色
|
||||
else
|
||||
*addr = BKcolor; // 背景色
|
||||
|
||||
++addr;
|
||||
}
|
||||
++font_ptr;
|
||||
}
|
||||
}
|
@ -1,372 +0,0 @@
|
||||
#include "textui.h"
|
||||
|
||||
#include <driver/uart/uart.h>
|
||||
#include "screen_manager.h"
|
||||
#include <common/atomic.h>
|
||||
#include <common/errno.h>
|
||||
#include <common/printk.h>
|
||||
#include <common/string.h>
|
||||
|
||||
struct scm_ui_framework_t textui_framework;
|
||||
static spinlock_t __window_id_lock = {1};
|
||||
static uint32_t __window_max_id = 0;
|
||||
|
||||
// 暂时初始化16080个初始字符对象以及67个虚拟行对象
|
||||
#define INITIAL_CHARS 16080
|
||||
#define INITIAL_VLINES (int)(1080 / 16)
|
||||
static struct textui_char_chromatic_t __initial_chars[INITIAL_CHARS] = {0};
|
||||
static struct textui_vline_chromatic_t __initial_vlines[INITIAL_VLINES] = {0};
|
||||
static struct textui_window_t __initial_window = {0}; // 初始窗口
|
||||
static struct textui_private_info_t __private_info = {0};
|
||||
static struct List __windows_list;
|
||||
static spinlock_t change_lock;
|
||||
|
||||
// 用于标记是否允许输出到屏幕
|
||||
static atomic_t __put_window_enable_flag = {1};
|
||||
|
||||
/**
|
||||
* @brief 初始化window对象
|
||||
*
|
||||
* @param window 窗口对象
|
||||
* @param flags 标志位
|
||||
* @param vlines_num 虚拟行的总数
|
||||
* @param vlines_ptr 虚拟行数组指针
|
||||
* @param cperline 每行最大的字符数
|
||||
*/
|
||||
static int __textui_init_window(struct textui_window_t *window, uint8_t flags, uint16_t vlines_num, void *vlines_ptr,
|
||||
uint16_t cperline)
|
||||
{
|
||||
memset((window), 0, sizeof(struct textui_window_t));
|
||||
list_init(&(window)->list);
|
||||
window->lock.lock = 1;
|
||||
spin_lock(&__window_id_lock);
|
||||
window->id = __window_max_id++;
|
||||
spin_unlock(&__window_id_lock);
|
||||
window->flags = flags;
|
||||
window->vlines_num = vlines_num;
|
||||
window->vlines_used = 1;
|
||||
window->top_vline = 0;
|
||||
window->vline_operating = 0;
|
||||
window->chars_per_line = cperline;
|
||||
if (textui_is_chromatic(flags))
|
||||
window->vlines.chromatic = vlines_ptr;
|
||||
else
|
||||
window->vlines.normal = vlines_ptr;
|
||||
list_add(&__windows_list, &(window)->list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化虚拟行对象
|
||||
*
|
||||
* @param vline 虚拟行对象指针
|
||||
* @param chars_ptr 字符对象数组指针
|
||||
*/
|
||||
#define __textui_init_vline(vline, chars_ptr) \
|
||||
do \
|
||||
{ \
|
||||
memset(vline, 0, sizeof(struct textui_vline_chromatic_t)); \
|
||||
(vline)->index = 0; \
|
||||
(vline)->chars = chars_ptr; \
|
||||
} while (0)
|
||||
|
||||
int textui_install_handler(struct scm_buffer_info_t *buf)
|
||||
{
|
||||
// return printk_init(buf);
|
||||
c_uart_send_str(COM1, "textui_install_handler\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_uninstall_handler(void *args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_enable_handler(void *args)
|
||||
{
|
||||
c_uart_send_str(COM1, "textui_enable_handler\n");
|
||||
atomic_cmpxchg(&__put_window_enable_flag, 0, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_disable_handler(void *args)
|
||||
{
|
||||
c_uart_send_str(COM1, "textui_disable_handler\n");
|
||||
atomic_set(&__put_window_enable_flag, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int textui_change_handler(struct scm_buffer_info_t *buf)
|
||||
{
|
||||
memcpy((void *)buf->vaddr, (void *)(textui_framework.buf->vaddr), textui_framework.buf->size);
|
||||
textui_framework.buf = buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct scm_ui_framework_operations_t textui_ops = {
|
||||
.install = &textui_install_handler,
|
||||
.uninstall = &textui_uninstall_handler,
|
||||
.change = &textui_change_handler,
|
||||
.enable = &textui_enable_handler,
|
||||
.disable = &textui_disable_handler,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 获取textui的帧缓冲区能容纳的内容的行数
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t __textui_get_actual_lines()
|
||||
{
|
||||
return __private_info.actual_line;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取当前渲染的窗口的id
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint32_t __textui_get_current_window_id()
|
||||
{
|
||||
return __private_info.current_window->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 插入换行
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @return int
|
||||
*/
|
||||
static int __textui_new_line(struct textui_window_t *window, uint16_t vline_id)
|
||||
{
|
||||
// todo: 支持在两个虚拟行之间插入一个新行
|
||||
|
||||
++window->vline_operating;
|
||||
|
||||
if (unlikely(window->vline_operating == window->vlines_num))
|
||||
window->vline_operating = 0;
|
||||
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
|
||||
memset(vline->chars, 0, sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
|
||||
vline->index = 0;
|
||||
|
||||
if (likely(window->vlines_used == window->vlines_num)) // 需要滚动屏幕
|
||||
{
|
||||
|
||||
++window->top_vline;
|
||||
|
||||
if (unlikely(window->top_vline >= window->vlines_num))
|
||||
window->top_vline = 0;
|
||||
|
||||
// 刷新所有行
|
||||
textui_refresh_vlines(window, window->top_vline, window->vlines_num);
|
||||
}
|
||||
else
|
||||
++window->vlines_used;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 真正向屏幕上输出字符的函数
|
||||
*
|
||||
* @param window
|
||||
* @param character
|
||||
* @return int
|
||||
*/
|
||||
static int __textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor,
|
||||
uint32_t BKcolor)
|
||||
{
|
||||
if (textui_is_chromatic(window->flags)) // 启用彩色字符
|
||||
{
|
||||
struct textui_vline_chromatic_t *vline = &window->vlines.chromatic[window->vline_operating];
|
||||
|
||||
vline->chars[vline->index].c = character;
|
||||
vline->chars[vline->index].FRcolor = FRcolor & 0xffffff;
|
||||
vline->chars[vline->index].BKcolor = BKcolor & 0xffffff;
|
||||
++vline->index;
|
||||
textui_refresh_characters(window, window->vline_operating, vline->index - 1, 1);
|
||||
// 换行
|
||||
// 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
|
||||
if (vline->index > window->chars_per_line)
|
||||
{
|
||||
__textui_new_line(window, window->vline_operating);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// todo: 支持纯文本字符
|
||||
while (1)
|
||||
pause();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在指定窗口上输出一个字符
|
||||
*
|
||||
* @param window 窗口
|
||||
* @param character 字符
|
||||
* @param FRcolor 前景色(RGB)
|
||||
* @param BKcolor 背景色(RGB)
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
|
||||
{
|
||||
if (unlikely(character == '\0'))
|
||||
return 0;
|
||||
if (!textui_is_chromatic(window->flags)) // 暂不支持纯文本窗口
|
||||
return 0;
|
||||
|
||||
// uint64_t rflags = 0; // 加锁后rflags存储到这里
|
||||
spin_lock_no_preempt(&window->lock);
|
||||
c_uart_send(COM1, character);
|
||||
// 如果禁止输出,直接返回
|
||||
if(atomic_read(&__put_window_enable_flag) == 0)
|
||||
{
|
||||
spin_unlock_no_preempt(&window->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (unlikely(character == '\n'))
|
||||
{
|
||||
// 换行时还需要输出\r
|
||||
c_uart_send(COM1, '\r');
|
||||
__textui_new_line(window, window->vline_operating);
|
||||
// spin_unlock_irqrestore(&window->lock, rflags);
|
||||
spin_unlock_no_preempt(&window->lock);
|
||||
return 0;
|
||||
}
|
||||
else if (character == '\t') // 输出制表符
|
||||
{
|
||||
int space_to_print = 8 - window->vlines.chromatic[window->vline_operating].index % 8;
|
||||
|
||||
while (space_to_print--)
|
||||
{
|
||||
__textui_putchar_window(window, ' ', FRcolor, BKcolor);
|
||||
}
|
||||
}
|
||||
else if (character == '\b') // 退格
|
||||
{
|
||||
char bufff[128] = {0};
|
||||
--(window->vlines.chromatic[window->vline_operating].index);
|
||||
{
|
||||
uint16_t tmp = window->vlines.chromatic[window->vline_operating].index;
|
||||
if (tmp >= 0)
|
||||
{
|
||||
window->vlines.chromatic[window->vline_operating].chars[tmp].c = ' ';
|
||||
window->vlines.chromatic[window->vline_operating].chars[tmp].BKcolor = BKcolor & 0xffffff;
|
||||
textui_refresh_characters(window, window->vline_operating, tmp, 1);
|
||||
}
|
||||
}
|
||||
// 需要向上缩一行
|
||||
if (window->vlines.chromatic[window->vline_operating].index <= 0)
|
||||
{
|
||||
window->vlines.chromatic[window->vline_operating].index = 0;
|
||||
memset(window->vlines.chromatic[window->vline_operating].chars, 0,
|
||||
sizeof(struct textui_char_chromatic_t) * window->chars_per_line);
|
||||
--(window->vline_operating);
|
||||
if (unlikely(window->vline_operating < 0))
|
||||
window->vline_operating = window->vlines_num - 1;
|
||||
|
||||
// 考虑是否向上滚动
|
||||
if (likely(window->vlines_used > __private_info.actual_line))
|
||||
{
|
||||
--window->top_vline;
|
||||
if (unlikely(window->top_vline < 0))
|
||||
window->top_vline = window->vlines_num - 1;
|
||||
}
|
||||
--window->vlines_used;
|
||||
textui_refresh_vlines(window, window->top_vline, __private_info.actual_line);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (window->vlines.chromatic[window->vline_operating].index == window->chars_per_line)
|
||||
__textui_new_line(window, window->vline_operating);
|
||||
__textui_putchar_window(window, character, FRcolor, BKcolor);
|
||||
}
|
||||
|
||||
// spin_unlock_irqrestore(&window->lock, rflags);
|
||||
spin_unlock_no_preempt(&window->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在默认窗口上输出一个字符
|
||||
*
|
||||
* @param character 字符
|
||||
* @param FRcolor 前景色(RGB)
|
||||
* @param BKcolor 背景色(RGB)
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor)
|
||||
{
|
||||
|
||||
return textui_putchar_window(__private_info.default_window, character, FRcolor, BKcolor);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 初始化text ui框架
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int textui_init()
|
||||
{
|
||||
spin_init(&change_lock);
|
||||
|
||||
spin_init(&__window_id_lock);
|
||||
__window_max_id = 0;
|
||||
list_init(&__windows_list);
|
||||
memset(&textui_framework, 0, sizeof(struct scm_ui_framework_t));
|
||||
memset(&__private_info, 0, sizeof(struct textui_private_info_t));
|
||||
|
||||
io_mfence();
|
||||
char name[] = "textUI";
|
||||
strcpy(textui_framework.name, name);
|
||||
|
||||
textui_framework.ui_ops = &textui_ops;
|
||||
textui_framework.type = 0;
|
||||
|
||||
// 注册框架到屏幕管理器
|
||||
int retval = scm_register(&textui_framework);
|
||||
if (retval != 0)
|
||||
{
|
||||
c_uart_send_str(COM1, "text ui init failed\n");
|
||||
while (1)
|
||||
pause();
|
||||
}
|
||||
|
||||
uint16_t chars_per_vline = textui_framework.buf->width / TEXTUI_CHAR_WIDTH;
|
||||
uint16_t total_vlines = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
|
||||
int cnt = chars_per_vline * total_vlines;
|
||||
|
||||
struct textui_vline_chromatic_t *vl_ptr = __initial_vlines;
|
||||
struct textui_char_chromatic_t *ch_ptr = __initial_chars;
|
||||
|
||||
// 初始化虚拟行
|
||||
for (int i = 0; i < total_vlines; ++i)
|
||||
{
|
||||
__textui_init_vline((vl_ptr + i), (ch_ptr + i * chars_per_vline));
|
||||
}
|
||||
|
||||
// 初始化窗口
|
||||
__textui_init_window((&__initial_window), TEXTUI_WF_CHROMATIC, total_vlines, __initial_vlines, chars_per_vline);
|
||||
__private_info.current_window = &__initial_window;
|
||||
__private_info.default_window = &__initial_window;
|
||||
__private_info.actual_line = textui_framework.buf->height / TEXTUI_CHAR_HEIGHT;
|
||||
|
||||
c_uart_send_str(COM1, "text ui initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void enable_textui()
|
||||
{
|
||||
scm_framework_enable(&textui_framework);
|
||||
}
|
||||
|
||||
void disable_textui()
|
||||
{
|
||||
scm_framework_disable(&textui_framework);
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
#include <common/sys/types.h>
|
||||
#include <common/spinlock.h>
|
||||
|
||||
/*
|
||||
textui中的几个对象的关系:
|
||||
|
||||
|
||||
textui_vline_normal_t
|
||||
+--------------------------------+
|
||||
| | textui_char_normal_t
|
||||
textui_window_t | chars: textui_char_normal_t * | +--------------------------+
|
||||
+----------------------------+ | | | |
|
||||
| | +------> +--------> c: char |
|
||||
| list:List | | | index: int16_t | +--------------------------+
|
||||
| vlines_num:int16_t | | | |
|
||||
| vlines_used:int16_t | | +--------------------------------+
|
||||
| | |
|
||||
| vlines +-----+ textui_char_chromatic_t
|
||||
| | | textui_vline_chromatic_t +--------------------------+
|
||||
| top_vline:int16_t | | +-------------------------------------+ | |
|
||||
| vline_operating:int16_t | | | | | c: uint16_t |
|
||||
| chars_per_line:int16_t | | | chars: textui_char_chromatic_t * | | |
|
||||
| flags:uint8_t | | | | | FRcolor:24 |
|
||||
| lock:spinlock_t | +------> +---> |
|
||||
| | | index: int16_t | | BKcolor:24 |
|
||||
| | | | | |
|
||||
+----------------------------+ +-------------------------------------+ +--------------------------+
|
||||
*/
|
||||
|
||||
// 文本窗口标志位
|
||||
// 文本窗口是否为彩色
|
||||
#define TEXTUI_WF_CHROMATIC (1 << 0)
|
||||
|
||||
// 窗口是否启用彩色字符
|
||||
#define textui_is_chromatic(flag) ((flag)&TEXTUI_WF_CHROMATIC)
|
||||
|
||||
// 每个字符的宽度和高度(像素)
|
||||
#define TEXTUI_CHAR_WIDTH 8
|
||||
#define TEXTUI_CHAR_HEIGHT 16
|
||||
|
||||
/**
|
||||
* @brief 黑白字符对象
|
||||
*
|
||||
*/
|
||||
struct textui_char_normal_t
|
||||
{
|
||||
char c;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 彩色字符对象
|
||||
*
|
||||
*/
|
||||
struct textui_char_chromatic_t
|
||||
{
|
||||
unsigned c : 16;
|
||||
|
||||
// 前景色
|
||||
unsigned FRcolor : 24; // rgb
|
||||
|
||||
// 背景色
|
||||
unsigned BKcolor : 24; // rgb
|
||||
};
|
||||
|
||||
// 注意!!! 请保持vline结构体的大小、成员变量命名相等!
|
||||
/**
|
||||
* @brief 单色显示的虚拟行结构体
|
||||
*
|
||||
*/
|
||||
struct textui_vline_normal_t
|
||||
{
|
||||
struct textui_char_normal_t *chars; // 字符对象数组
|
||||
int16_t index; // 当前操作的位置
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 彩色显示的虚拟行结构体
|
||||
*
|
||||
*/
|
||||
struct textui_vline_chromatic_t
|
||||
{
|
||||
struct textui_char_chromatic_t *chars;
|
||||
int16_t index; // 当前操作的位置
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief textu ui 框架的文本窗口结构体
|
||||
*
|
||||
*/
|
||||
struct textui_window_t
|
||||
{
|
||||
struct List list;
|
||||
|
||||
uint32_t id; // 窗口id
|
||||
int16_t vlines_num; // 虚拟行总数
|
||||
int16_t vlines_used; // 当前已经使用了的虚拟行总数
|
||||
|
||||
// 指向虚拟行的数组的指针(二选一)
|
||||
union
|
||||
{
|
||||
struct textui_vline_normal_t *normal;
|
||||
struct textui_vline_chromatic_t *chromatic;
|
||||
} vlines;
|
||||
|
||||
int16_t top_vline; // 位于最顶上的那一个虚拟行的行号
|
||||
int16_t vline_operating; // 正在操作的vline
|
||||
int16_t chars_per_line; // 每行最大容纳的字符数
|
||||
uint8_t flags; // 窗口flag
|
||||
spinlock_t lock; // 窗口操作锁
|
||||
};
|
||||
|
||||
struct textui_private_info_t
|
||||
{
|
||||
int16_t actual_line; // 真实行的数量
|
||||
struct textui_window_t *current_window; // 当前的主窗口
|
||||
struct textui_window_t *default_window; // 默认print到的窗口
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 重新渲染整个虚拟行
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_vline(struct textui_window_t *window, uint16_t vline_id);
|
||||
|
||||
int textui_refresh_vlines(struct textui_window_t *window, uint16_t start, uint16_t count);
|
||||
|
||||
/**
|
||||
* @brief 刷新某个虚拟行的连续n个字符对象
|
||||
*
|
||||
* @param window 窗口结构体
|
||||
* @param vline_id 虚拟行号
|
||||
* @param start 起始字符号
|
||||
* @param count 要刷新的字符数量
|
||||
* @return int 错误码
|
||||
*/
|
||||
int textui_refresh_characters(struct textui_window_t *window, uint16_t vline_id, uint16_t start, uint16_t count);
|
||||
|
||||
/**
|
||||
* @brief 在指定窗口上输出一个字符
|
||||
*
|
||||
* @param window 窗口
|
||||
* @param character 字符
|
||||
* @param FRcolor 前景色(RGB)
|
||||
* @param BKcolor 背景色(RGB)
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar_window(struct textui_window_t *window, uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
|
||||
|
||||
/**
|
||||
* @brief 在默认窗口上输出一个字符
|
||||
*
|
||||
* @param character 字符
|
||||
* @param FRcolor 前景色(RGB)
|
||||
* @param BKcolor 背景色(RGB)
|
||||
* @return int
|
||||
*/
|
||||
int textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
|
||||
|
||||
/**
|
||||
* @brief 获取textui的帧缓冲区能容纳的内容的行数
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint16_t __textui_get_actual_lines();
|
||||
|
||||
/**
|
||||
* @brief 获取当前渲染的窗口的id
|
||||
*
|
||||
* @return uint16_t
|
||||
*/
|
||||
uint32_t __textui_get_current_window_id();
|
||||
|
||||
/**
|
||||
* @brief 初始化text ui框架
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int textui_init();
|
||||
|
||||
void enable_textui();
|
||||
|
||||
void disable_textui();
|
BIN
kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes
Normal file
BIN
kernel/src/libs/lib_ui/font/binaries/spleen-8x16.raw_bytes
Normal file
Binary file not shown.
90
kernel/src/libs/lib_ui/font/mod.rs
Normal file
90
kernel/src/libs/lib_ui/font/mod.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use super::textui::GlyphMapping;
|
||||
|
||||
pub mod spleen_font;
|
||||
|
||||
pub use spleen_font::SPLEEN_FONT_8x16 as FONT_8x16;
|
||||
|
||||
/// Stores the font bitmap and some additional info for each font.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BitmapFont<'a> {
|
||||
/// The raw bitmap data for the font.
|
||||
bitmap: RawBitMap<'a>,
|
||||
|
||||
/// The char to glyph mapping.
|
||||
glyph_mapping: &'a dyn GlyphMapping,
|
||||
|
||||
/// The size of each character in the raw bitmap data.
|
||||
size: Size,
|
||||
|
||||
bytes_per_char: usize,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'a> BitmapFont<'a> {
|
||||
pub const fn new(
|
||||
bitmap: RawBitMap<'a>,
|
||||
glyph_mapping: &'a dyn GlyphMapping,
|
||||
size: Size,
|
||||
) -> Self {
|
||||
Self {
|
||||
bitmap,
|
||||
glyph_mapping,
|
||||
size,
|
||||
bytes_per_char: (size.width + 7) / 8 * size.height,
|
||||
}
|
||||
}
|
||||
/// Return the width of each character.
|
||||
pub const fn width(&self) -> u32 {
|
||||
self.size.width as u32
|
||||
}
|
||||
|
||||
/// Return the height of each character.
|
||||
pub const fn height(&self) -> u32 {
|
||||
self.size.height as u32
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn char_map(&self, character: char) -> &'a [u8] {
|
||||
let index = self.glyph_mapping.index(character);
|
||||
let pos = index * self.bytes_per_char;
|
||||
|
||||
return &self.bitmap.data[pos..pos + self.bytes_per_char];
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Size {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
}
|
||||
|
||||
impl Size {
|
||||
pub const fn new(width: usize, height: usize) -> Self {
|
||||
Self { width, height }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct RawBitMap<'a> {
|
||||
pub data: &'a [u8],
|
||||
pub size: Size,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl RawBitMap<'_> {
|
||||
pub const fn new(data: &'static [u8], width: usize) -> Self {
|
||||
let size = Size {
|
||||
width: 128,
|
||||
height: data.len() / width / 8,
|
||||
};
|
||||
Self { data, size }
|
||||
}
|
||||
|
||||
pub const fn size(&self) -> Size {
|
||||
self.size
|
||||
}
|
||||
|
||||
pub const fn len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
}
|
25
kernel/src/libs/lib_ui/font/spleen_font.rs
Normal file
25
kernel/src/libs/lib_ui/font/spleen_font.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use crate::libs::lib_ui::textui::GlyphMapping;
|
||||
|
||||
use super::{BitmapFont, RawBitMap, Size};
|
||||
|
||||
struct Mapping;
|
||||
|
||||
impl GlyphMapping for Mapping {
|
||||
#[inline(always)]
|
||||
fn index(&self, c: char) -> usize {
|
||||
let c = c as usize;
|
||||
match c {
|
||||
0..=255 => c,
|
||||
_ => '?' as usize - ' ' as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const SPLEEN_GLYPH_MAPPING: Mapping = Mapping;
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const SPLEEN_FONT_8x16: BitmapFont<'static> = BitmapFont::new(
|
||||
RawBitMap::new(include_bytes!("binaries/spleen-8x16.raw_bytes"), 128),
|
||||
&SPLEEN_GLYPH_MAPPING,
|
||||
Size::new(8, 16),
|
||||
);
|
4
kernel/src/libs/lib_ui/mod.rs
Normal file
4
kernel/src/libs/lib_ui/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod font;
|
||||
pub mod screen_manager;
|
||||
pub mod textui;
|
||||
pub mod textui_no_alloc;
|
58
kernel/src/libs/lib_ui/screen_manager.h
Normal file
58
kernel/src/libs/lib_ui/screen_manager.h
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include <common/sys/types.h>
|
||||
#include <common/glib.h>
|
||||
|
||||
// 帧缓冲区标志位
|
||||
#define SCM_BF_FB (1 << 0) // 当前buffer是设备显存中的帧缓冲区
|
||||
#define SCM_BF_DB (1 << 1) // 当前buffer是双缓冲
|
||||
#define SCM_BF_TEXT (1 << 2) // 使用文本模式
|
||||
#define SCM_BF_PIXEL (1 << 3) // 使用图像模式
|
||||
|
||||
// ui框架类型
|
||||
#define SCM_FRAMWORK_TYPE_TEXT (uint8_t)0
|
||||
#define SCM_FRAMWORK_TYPE_GUI (uint8_t)1
|
||||
|
||||
/**
|
||||
* @brief 帧缓冲区信息结构体
|
||||
*
|
||||
*/
|
||||
struct scm_buffer_info_t
|
||||
{
|
||||
uint32_t width; // 帧缓冲区宽度(pixel或columns)
|
||||
uint32_t height; // 帧缓冲区高度(pixel或lines)
|
||||
uint32_t size; // 帧缓冲区大小(bytes)
|
||||
uint32_t bit_depth; // 像素点位深度
|
||||
|
||||
uint64_t vaddr; // 帧缓冲区的地址
|
||||
uint64_t flags; // 帧缓冲区标志位
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化屏幕管理模块
|
||||
*
|
||||
*/
|
||||
extern void scm_init();
|
||||
|
||||
/**
|
||||
* @brief 当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
||||
*
|
||||
*/
|
||||
extern void scm_reinit();
|
||||
|
||||
/**
|
||||
* @brief 允许双缓冲区
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
extern int scm_enable_double_buffer();
|
||||
|
||||
/**
|
||||
* @brief 允许往窗口打印信息
|
||||
*
|
||||
*/
|
||||
extern void scm_enable_put_to_window();
|
||||
/**
|
||||
* @brief 禁止往窗口打印信息
|
||||
*
|
||||
*/
|
||||
extern void scm_disable_put_to_window();
|
475
kernel/src/libs/lib_ui/screen_manager.rs
Normal file
475
kernel/src/libs/lib_ui/screen_manager.rs
Normal file
@ -0,0 +1,475 @@
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
intrinsics::unlikely,
|
||||
sync::atomic::{AtomicBool, AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
driver::uart::uart::{c_uart_send_str, UartPort},
|
||||
include::bindings::bindings::{
|
||||
scm_buffer_info_t, video_frame_buffer_info, video_reinitialize, video_set_refresh_target,
|
||||
},
|
||||
libs::{rwlock::RwLock, spinlock::SpinLock},
|
||||
mm::VirtAddr,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
use super::textui_no_alloc::textui_init_no_alloc;
|
||||
|
||||
lazy_static! {
|
||||
/// 全局的UI框架列表
|
||||
pub static ref SCM_FRAMEWORK_LIST: SpinLock<LinkedList<Arc<dyn ScmUiFramework>>> =
|
||||
SpinLock::new(LinkedList::new());
|
||||
/// 当前在使用的UI框架
|
||||
pub static ref CURRENT_FRAMEWORK: RwLock<Option<Arc<dyn ScmUiFramework>>> = RwLock::new(None);
|
||||
|
||||
}
|
||||
|
||||
/// 是否启用双缓冲
|
||||
pub static SCM_DOUBLE_BUFFER_ENABLED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
bitflags! {
|
||||
pub struct ScmBufferFlag:u8 {
|
||||
// 帧缓冲区标志位
|
||||
const SCM_BF_FB = 1 << 0; // 当前buffer是设备显存中的帧缓冲区
|
||||
const SCM_BF_DB = 1 << 1; // 当前buffer是双缓冲
|
||||
const SCM_BF_TEXT = 1 << 2; // 使用文本模式
|
||||
const SCM_BF_PIXEL = 1 << 3; // 使用图像模式
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum ScmFramworkType {
|
||||
Text,
|
||||
Gui,
|
||||
Unused,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum ScmBuffer {
|
||||
DeviceBuffer(Option<VirtAddr>),
|
||||
DoubleBuffer(Option<Box<[u32]>>),
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct ScmBufferInfo {
|
||||
width: u32, // 帧缓冲区宽度(pixel或columns)
|
||||
height: u32, // 帧缓冲区高度(pixel或lines)
|
||||
size: u32, // 帧缓冲区大小(bytes)
|
||||
bit_depth: u32, // 像素点位深度
|
||||
pub buf: ScmBuffer,
|
||||
flags: ScmBufferFlag, // 帧缓冲区标志位
|
||||
}
|
||||
impl Clone for ScmBufferInfo {
|
||||
fn clone(&self) -> Self {
|
||||
match self.buf {
|
||||
ScmBuffer::DeviceBuffer(_) => ScmBufferInfo {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
size: self.size,
|
||||
bit_depth: self.bit_depth,
|
||||
flags: self.flags,
|
||||
buf: ScmBuffer::DeviceBuffer(Option::None),
|
||||
},
|
||||
ScmBuffer::DoubleBuffer(_) => ScmBufferInfo {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
size: self.size,
|
||||
bit_depth: self.bit_depth,
|
||||
flags: self.flags,
|
||||
buf: ScmBuffer::DoubleBuffer(Option::None),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScmBufferInfo {
|
||||
/// 创建新的帧缓冲区信息
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `buf_type` 帧缓冲区类型
|
||||
///
|
||||
/// ## 返回值
|
||||
///
|
||||
/// - `Result<Self, SystemError>` 创建成功返回新的帧缓冲区结构体,创建失败返回错误码
|
||||
pub fn new(buf_type: ScmBufferFlag) -> Result<Self, SystemError> {
|
||||
if unlikely(SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == false) {
|
||||
let buf_info = ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
|
||||
|
||||
return Ok(buf_info);
|
||||
} else {
|
||||
// 创建双缓冲区
|
||||
let mut frame_buffer_info: ScmBufferInfo =
|
||||
ScmBufferInfo::from(unsafe { &video_frame_buffer_info });
|
||||
|
||||
frame_buffer_info.flags = buf_type;
|
||||
// 这里还是改成使用box来存储数组,如果直接用vec存储,在multiboot2_iter那里会报错,不知为何
|
||||
frame_buffer_info.buf = ScmBuffer::DoubleBuffer(Some(
|
||||
Box::new(vec![
|
||||
0;
|
||||
unsafe { (video_frame_buffer_info.size / 4) as usize }
|
||||
])
|
||||
.into_boxed_slice(),
|
||||
));
|
||||
|
||||
return Ok(frame_buffer_info);
|
||||
}
|
||||
}
|
||||
|
||||
// 重构了video后可以删除
|
||||
fn vaddr(&mut self) -> VirtAddr {
|
||||
match &self.buf {
|
||||
ScmBuffer::DeviceBuffer(vaddr) => {
|
||||
if !vaddr.is_none() {
|
||||
vaddr.unwrap()
|
||||
} else {
|
||||
return VirtAddr::new(0);
|
||||
}
|
||||
}
|
||||
ScmBuffer::DoubleBuffer(buf) => {
|
||||
if !buf.is_none() {
|
||||
let address = self.buf().as_ptr();
|
||||
VirtAddr::new(address as usize)
|
||||
} else {
|
||||
return VirtAddr::new(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn buf(&mut self) -> &mut [u32] {
|
||||
let len = self.buf_size() / 4;
|
||||
match &mut self.buf {
|
||||
ScmBuffer::DoubleBuffer(buf) => match buf.as_mut() {
|
||||
Some(buf) => buf,
|
||||
None => panic!("Buffer is none"),
|
||||
},
|
||||
ScmBuffer::DeviceBuffer(vaddr) => match vaddr.as_mut() {
|
||||
Some(vaddr) => {
|
||||
let buf: &mut [u32] = unsafe {
|
||||
core::slice::from_raw_parts_mut(vaddr.data() as *mut u32, len as usize)
|
||||
};
|
||||
return buf;
|
||||
}
|
||||
None => panic!("Buffer is none"),
|
||||
},
|
||||
}
|
||||
}
|
||||
pub fn buf_size(&self) -> u32 {
|
||||
self.size
|
||||
}
|
||||
pub fn buf_height(&self) -> u32 {
|
||||
self.height
|
||||
}
|
||||
pub fn buf_width(&self) -> u32 {
|
||||
self.width
|
||||
}
|
||||
pub fn is_double_buffer(&self) -> bool {
|
||||
match &self.buf {
|
||||
ScmBuffer::DoubleBuffer(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
pub fn is_device_buffer(&self) -> bool {
|
||||
match &self.buf {
|
||||
ScmBuffer::DeviceBuffer(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重构了video后可以删除
|
||||
impl From<&scm_buffer_info_t> for ScmBufferInfo {
|
||||
fn from(value: &scm_buffer_info_t) -> Self {
|
||||
Self {
|
||||
width: value.width,
|
||||
height: value.height,
|
||||
size: value.size,
|
||||
bit_depth: value.bit_depth,
|
||||
buf: ScmBuffer::DeviceBuffer(Some(VirtAddr::new(value.vaddr as usize))),
|
||||
flags: ScmBufferFlag::from_bits_truncate(value.flags as u8),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Into<scm_buffer_info_t> for ScmBufferInfo {
|
||||
fn into(mut self) -> scm_buffer_info_t {
|
||||
let vaddr = self.vaddr();
|
||||
scm_buffer_info_t {
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
size: self.size,
|
||||
bit_depth: self.bit_depth,
|
||||
vaddr: vaddr.data() as u64,
|
||||
flags: self.flags.bits as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct ScmUiFrameworkId(u32);
|
||||
|
||||
impl ScmUiFrameworkId {
|
||||
/// 分配一个新的框架id
|
||||
pub fn new() -> Self {
|
||||
static MAX_ID: AtomicU32 = AtomicU32::new(0);
|
||||
return ScmUiFrameworkId(MAX_ID.fetch_add(1, Ordering::SeqCst));
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ScmUiFrameworkMetadata {
|
||||
id: ScmUiFrameworkId,
|
||||
name: String,
|
||||
framework_type: ScmFramworkType,
|
||||
pub buf_info: ScmBufferInfo,
|
||||
}
|
||||
|
||||
impl ScmUiFrameworkMetadata {
|
||||
pub fn new(name: String, framework_type: ScmFramworkType) -> Self {
|
||||
match framework_type {
|
||||
ScmFramworkType::Text => {
|
||||
let result = ScmUiFrameworkMetadata {
|
||||
id: ScmUiFrameworkId::new(),
|
||||
name,
|
||||
framework_type: ScmFramworkType::Text,
|
||||
buf_info: ScmBufferInfo::new(ScmBufferFlag::SCM_BF_TEXT).unwrap(),
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
ScmFramworkType::Gui => todo!(),
|
||||
ScmFramworkType::Unused => todo!(),
|
||||
}
|
||||
}
|
||||
pub fn buf_info(&self) -> ScmBufferInfo {
|
||||
return self.buf_info.clone();
|
||||
}
|
||||
pub fn set_buf_info(&mut self, buf_info: ScmBufferInfo) {
|
||||
self.buf_info = buf_info;
|
||||
}
|
||||
pub fn buf_is_none(&self) -> bool {
|
||||
match &self.buf_info.buf {
|
||||
ScmBuffer::DeviceBuffer(vaddr) => {
|
||||
return vaddr.is_none();
|
||||
}
|
||||
ScmBuffer::DoubleBuffer(buf) => {
|
||||
return buf.is_none();
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn buf(&mut self) -> &mut [u32] {
|
||||
if self.buf_is_none() {
|
||||
panic!("buf is none");
|
||||
}
|
||||
self.buf_info.buf()
|
||||
}
|
||||
}
|
||||
pub trait ScmUiFramework: Sync + Send + Debug {
|
||||
// 安装ui框架的回调函数
|
||||
fn install(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 卸载ui框架的回调函数
|
||||
fn uninstall(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 启用ui框架的回调函数
|
||||
fn enable(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 禁用ui框架的回调函数
|
||||
fn disable(&self) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
// 改变ui框架的帧缓冲区的回调函数
|
||||
fn change(&self, _buf: ScmBufferInfo) -> Result<i32, SystemError> {
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
/// @brief 获取ScmUiFramework的元数据
|
||||
/// @return 成功:Ok(ScmUiFramework的元数据)
|
||||
/// 失败:Err(错误码)
|
||||
fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
|
||||
// 若文件系统没有实现此方法,则返回“不支持”
|
||||
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化屏幕控制模块
|
||||
///
|
||||
/// ## 调用时机
|
||||
///
|
||||
/// 该函数在内核启动的早期进行调用。调用时,内存管理模块尚未初始化。
|
||||
#[no_mangle]
|
||||
pub extern "C" fn scm_init() {
|
||||
SCM_DOUBLE_BUFFER_ENABLED.store(false, Ordering::SeqCst); // 禁用双缓冲
|
||||
|
||||
textui_init_no_alloc();
|
||||
|
||||
c_uart_send_str(UartPort::COM1.to_u16(), "\nfinish_scm_init\n\0".as_ptr());
|
||||
}
|
||||
|
||||
/// 启用某个ui框架,将它的帧缓冲区渲染到屏幕上
|
||||
/// ## 参数
|
||||
///
|
||||
/// - framework 要启动的ui框架
|
||||
|
||||
pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
|
||||
// 获取信息
|
||||
let metadata = framework.metadata()?;
|
||||
|
||||
// if metadata.buf_info.buf.is_null() {
|
||||
// return Err(SystemError::EINVAL);
|
||||
// }
|
||||
let mut current_framework = CURRENT_FRAMEWORK.write();
|
||||
|
||||
if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) == true {
|
||||
let buf: scm_buffer_info_t = metadata.buf_info.into();
|
||||
let retval = unsafe { video_set_refresh_target(buf) };
|
||||
if retval == 0 {
|
||||
framework.enable()?;
|
||||
}
|
||||
} else {
|
||||
framework.enable()?;
|
||||
}
|
||||
|
||||
current_framework.replace(framework);
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
/// 向屏幕管理器注册UI框架
|
||||
///
|
||||
/// ## 参数
|
||||
/// - framework 框架结构体
|
||||
|
||||
pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError> {
|
||||
// 把ui框架加入链表
|
||||
|
||||
SCM_FRAMEWORK_LIST.lock().push_back(framework.clone());
|
||||
// 调用ui框架的回调函数以安装ui框架,并将其激活
|
||||
framework.install()?;
|
||||
|
||||
// 如果当前还没有框架获得了屏幕的控制权,就让其拿去
|
||||
if CURRENT_FRAMEWORK.read().is_none() {
|
||||
return scm_framework_enable(framework);
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// 允许双缓冲区
|
||||
#[no_mangle]
|
||||
pub extern "C" fn scm_enable_double_buffer() -> i32 {
|
||||
let r = true_scm_enable_double_buffer().unwrap_or_else(|e| e.to_posix_errno());
|
||||
if r.is_negative() {
|
||||
c_uart_send_str(
|
||||
UartPort::COM1.to_u16(),
|
||||
"scm enable double buffer fail.\n\0".as_ptr(),
|
||||
);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
fn true_scm_enable_double_buffer() -> Result<i32, SystemError> {
|
||||
if SCM_DOUBLE_BUFFER_ENABLED.load(Ordering::SeqCst) {
|
||||
// 已经开启了双缓冲区了, 直接退出
|
||||
return Ok(0);
|
||||
}
|
||||
let scm_list = SCM_FRAMEWORK_LIST.lock();
|
||||
if scm_list.is_empty() {
|
||||
// scm 框架链表为空
|
||||
return Ok(0);
|
||||
}
|
||||
drop(scm_list);
|
||||
SCM_DOUBLE_BUFFER_ENABLED.store(true, Ordering::SeqCst);
|
||||
// 创建双缓冲区
|
||||
let mut buf_info = ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
|
||||
let mut refresh_target_buf: scm_buffer_info_t = buf_info.clone().into();
|
||||
// 重构video后进行修改
|
||||
refresh_target_buf.vaddr = buf_info.vaddr().data() as u64;
|
||||
CURRENT_FRAMEWORK
|
||||
.write()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.change(buf_info)?;
|
||||
// 设置定时刷新的对象
|
||||
unsafe { video_set_refresh_target(refresh_target_buf) };
|
||||
// 遍历当前所有使用帧缓冲区的框架,更新为双缓冲区
|
||||
for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
|
||||
if !(*framework).metadata()?.buf_info.is_double_buffer() {
|
||||
let new_buf_info =
|
||||
ScmBufferInfo::new(ScmBufferFlag::SCM_BF_DB | ScmBufferFlag::SCM_BF_PIXEL)?;
|
||||
(*framework).change(new_buf_info)?;
|
||||
}
|
||||
}
|
||||
// 通知显示驱动,启动双缓冲
|
||||
unsafe { video_reinitialize(true) };
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
/// 允许往窗口打印信息
|
||||
#[no_mangle]
|
||||
pub fn scm_enable_put_to_window() {
|
||||
// mm之前要继续往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值
|
||||
if CURRENT_FRAMEWORK.read().is_none() {
|
||||
super::textui::ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
|
||||
} else {
|
||||
let r = CURRENT_FRAMEWORK
|
||||
.write()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.enable()
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
if r.is_negative() {
|
||||
c_uart_send_str(
|
||||
UartPort::COM1.to_u16(),
|
||||
"scm_enable_put_to_window() failed.\n\0".as_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 禁止往窗口打印信息
|
||||
#[no_mangle]
|
||||
pub fn scm_disable_put_to_window() {
|
||||
// mm之前要停止往窗口打印信息时,因为没有动态内存分配(rwlock与otion依然能用,但是textui并没有往scm注册),且使用的是textui,要直接修改textui里面的值
|
||||
if CURRENT_FRAMEWORK.read().is_none() {
|
||||
super::textui::ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
|
||||
assert!(super::textui::ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst) == false);
|
||||
} else {
|
||||
let r = CURRENT_FRAMEWORK
|
||||
.write()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.disable()
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
if r.is_negative() {
|
||||
c_uart_send_str(
|
||||
UartPort::COM1.to_u16(),
|
||||
"scm_disable_put_to_window() failed.\n\0".as_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 当内存管理单元被初始化之后,重新处理帧缓冲区问题
|
||||
#[no_mangle]
|
||||
pub extern "C" fn scm_reinit() -> i32 {
|
||||
let r = true_scm_reinit().unwrap_or_else(|e| e.to_posix_errno());
|
||||
if r.is_negative() {
|
||||
c_uart_send_str(UartPort::COM1.to_u16(), "scm reinit failed.\n\0".as_ptr());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
fn true_scm_reinit() -> Result<i32, SystemError> {
|
||||
unsafe { video_reinitialize(false) };
|
||||
|
||||
// 遍历当前所有使用帧缓冲区的框架,更新地址
|
||||
for framework in SCM_FRAMEWORK_LIST.lock().iter_mut() {
|
||||
if framework.metadata()?.buf_info().is_device_buffer() {
|
||||
framework.change(unsafe { ScmBufferInfo::from(&video_frame_buffer_info) })?;
|
||||
}
|
||||
}
|
||||
|
||||
scm_enable_put_to_window();
|
||||
|
||||
return Ok(0);
|
||||
}
|
19
kernel/src/libs/lib_ui/textui.h
Normal file
19
kernel/src/libs/lib_ui/textui.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
|
||||
/**
|
||||
* @brief 在默认窗口上输出一个字符
|
||||
*
|
||||
* @param character 字符
|
||||
* @param FRcolor 前景色(RGB)
|
||||
* @param BKcolor 背景色(RGB)
|
||||
* @return int
|
||||
*/
|
||||
extern int rs_textui_putchar(uint16_t character, uint32_t FRcolor, uint32_t BKcolor);
|
||||
|
||||
/**
|
||||
* @brief 初始化text ui框架
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
extern int textui_init();
|
967
kernel/src/libs/lib_ui/textui.rs
Normal file
967
kernel/src/libs/lib_ui/textui.rs
Normal file
@ -0,0 +1,967 @@
|
||||
use crate::{
|
||||
driver::uart::uart::{c_uart_send, c_uart_send_str, UartPort},
|
||||
include::bindings::bindings::video_frame_buffer_info,
|
||||
kinfo,
|
||||
libs::{lib_ui::font::FONT_8x16, spinlock::SpinLock},
|
||||
syscall::SystemError,
|
||||
};
|
||||
use alloc::{boxed::Box, collections::LinkedList, string::ToString};
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use core::{
|
||||
fmt::Debug,
|
||||
intrinsics::unlikely,
|
||||
ops::{Add, AddAssign, Sub},
|
||||
sync::atomic::{AtomicBool, AtomicI32, AtomicU32, Ordering},
|
||||
};
|
||||
|
||||
use super::{
|
||||
screen_manager::{
|
||||
scm_register, ScmBufferInfo, ScmFramworkType, ScmUiFramework, ScmUiFrameworkMetadata,
|
||||
},
|
||||
textui_no_alloc::no_init_textui_putchar_window,
|
||||
};
|
||||
|
||||
/// 声明全局的TEXTUI_FRAMEWORK
|
||||
static mut __TEXTUI_FRAMEWORK: Option<Box<TextUiFramework>> = None;
|
||||
|
||||
/// 每个字符的宽度和高度(像素)
|
||||
pub const TEXTUI_CHAR_WIDTH: u32 = 8;
|
||||
|
||||
pub const TEXTUI_CHAR_HEIGHT: u32 = 16;
|
||||
|
||||
pub static mut TEXTUI_IS_INIT: bool = false;
|
||||
|
||||
pub static ENABLE_PUT_TO_WINDOW: AtomicBool = AtomicBool::new(true);
|
||||
|
||||
/// 获取TEXTUI_FRAMEWORK的可变实例
|
||||
pub fn textui_framework() -> &'static mut TextUiFramework {
|
||||
return unsafe { __TEXTUI_FRAMEWORK.as_mut().unwrap() };
|
||||
}
|
||||
/// 初始化TEXTUI_FRAMEWORK
|
||||
pub unsafe fn textui_framwork_init() {
|
||||
if __TEXTUI_FRAMEWORK.is_none() {
|
||||
kinfo!("textuiframework init");
|
||||
let metadata = ScmUiFrameworkMetadata::new("TextUI".to_string(), ScmFramworkType::Text);
|
||||
// 为textui框架生成第一个窗口
|
||||
let vlines_num = (metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as usize;
|
||||
|
||||
let chars_num = (metadata.buf_info().buf_width() / TEXTUI_CHAR_WIDTH) as usize;
|
||||
|
||||
let initial_window = TextuiWindow::new(
|
||||
WindowFlag::TEXTUI_CHROMATIC,
|
||||
vlines_num as i32,
|
||||
chars_num as i32,
|
||||
);
|
||||
|
||||
let current_window: Arc<SpinLock<TextuiWindow>> = Arc::new(SpinLock::new(initial_window));
|
||||
|
||||
let default_window = current_window.clone();
|
||||
|
||||
// 生成窗口链表,并把上面窗口添加进textui框架的窗口链表中
|
||||
let window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>> =
|
||||
Arc::new(SpinLock::new(LinkedList::new()));
|
||||
window_list.lock().push_back(current_window.clone());
|
||||
|
||||
__TEXTUI_FRAMEWORK = Some(Box::new(TextUiFramework::new(
|
||||
metadata,
|
||||
window_list,
|
||||
current_window,
|
||||
default_window,
|
||||
)));
|
||||
} else {
|
||||
panic!("Try to init TEXTUI_FRAMEWORK twice!");
|
||||
}
|
||||
}
|
||||
// window标志位
|
||||
bitflags! {
|
||||
pub struct WindowFlag: u8 {
|
||||
// 采用彩色字符
|
||||
const TEXTUI_CHROMATIC = 1 << 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 黑白字符对象
|
||||
*
|
||||
*/
|
||||
#[derive(Clone, Debug)]
|
||||
struct TextuiCharNormal {
|
||||
_data: u8,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct LineId(i32);
|
||||
impl LineId {
|
||||
pub fn new(num: i32) -> Self {
|
||||
LineId(num)
|
||||
}
|
||||
|
||||
pub fn check(&self, max: i32) -> bool {
|
||||
self.0 < max && self.0 >= 0
|
||||
}
|
||||
|
||||
pub fn data(&self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl Add<i32> for LineId {
|
||||
type Output = LineId;
|
||||
fn add(self, rhs: i32) -> Self::Output {
|
||||
LineId::new(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
impl Sub<i32> for LineId {
|
||||
type Output = LineId;
|
||||
|
||||
fn sub(self, rhs: i32) -> Self::Output {
|
||||
LineId::new(self.0 - rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<i32> for LineId {
|
||||
fn into(self) -> i32 {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
impl Into<u32> for LineId {
|
||||
fn into(self) -> u32 {
|
||||
self.0.clone() as u32
|
||||
}
|
||||
}
|
||||
impl Into<usize> for LineId {
|
||||
fn into(self) -> usize {
|
||||
self.0.clone() as usize
|
||||
}
|
||||
}
|
||||
impl Sub<LineId> for LineId {
|
||||
type Output = LineId;
|
||||
|
||||
fn sub(mut self, rhs: LineId) -> Self::Output {
|
||||
self.0 -= rhs.0;
|
||||
return self;
|
||||
}
|
||||
}
|
||||
impl AddAssign<LineId> for LineId {
|
||||
fn add_assign(&mut self, rhs: LineId) {
|
||||
self.0 += rhs.0;
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
|
||||
pub struct LineIndex(i32);
|
||||
impl LineIndex {
|
||||
pub fn new(num: i32) -> Self {
|
||||
LineIndex(num)
|
||||
}
|
||||
pub fn check(&self, chars_per_line: i32) -> bool {
|
||||
self.0 < chars_per_line && self.0 >= 0
|
||||
}
|
||||
}
|
||||
impl Add<LineIndex> for LineIndex {
|
||||
type Output = LineIndex;
|
||||
|
||||
fn add(self, rhs: LineIndex) -> Self::Output {
|
||||
LineIndex::new(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
impl Add<i32> for LineIndex {
|
||||
// type Output = Self;
|
||||
type Output = LineIndex;
|
||||
|
||||
fn add(self, rhs: i32) -> Self::Output {
|
||||
LineIndex::new(self.0 + rhs)
|
||||
}
|
||||
}
|
||||
impl Sub<i32> for LineIndex {
|
||||
type Output = LineIndex;
|
||||
|
||||
fn sub(self, rhs: i32) -> Self::Output {
|
||||
LineIndex::new(self.0 - rhs)
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<i32> for LineIndex {
|
||||
fn into(self) -> i32 {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
impl Into<u32> for LineIndex {
|
||||
fn into(self) -> u32 {
|
||||
self.0.clone() as u32
|
||||
}
|
||||
}
|
||||
impl Into<usize> for LineIndex {
|
||||
fn into(self) -> usize {
|
||||
self.0.clone() as usize
|
||||
}
|
||||
}
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct FontColor(u32);
|
||||
#[allow(dead_code)]
|
||||
impl FontColor {
|
||||
pub const BLUE: FontColor = FontColor::new(0, 0, 0xff);
|
||||
pub const RED: FontColor = FontColor::new(0xff, 0, 0);
|
||||
pub const GREEN: FontColor = FontColor::new(0, 0xff, 0);
|
||||
pub const WHITE: FontColor = FontColor::new(0xff, 0xff, 0xff);
|
||||
pub const BLACK: FontColor = FontColor::new(0, 0, 0);
|
||||
pub const YELLOW: FontColor = FontColor::new(0xff, 0xff, 0);
|
||||
pub const ORANGE: FontColor = FontColor::new(0xff, 0x80, 0);
|
||||
pub const INDIGO: FontColor = FontColor::new(0x00, 0xff, 0xff);
|
||||
pub const PURPLE: FontColor = FontColor::new(0x80, 0x00, 0xff);
|
||||
|
||||
pub const fn new(r: u8, g: u8, b: u8) -> Self {
|
||||
let val = ((r as u32) << 16) | ((g as u32) << 8) | (b as u32);
|
||||
return FontColor(val & 0x00ffffff);
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for FontColor {
|
||||
fn from(value: u32) -> Self {
|
||||
return Self(value & 0x00ffffff);
|
||||
}
|
||||
}
|
||||
impl Into<usize> for FontColor {
|
||||
fn into(self) -> usize {
|
||||
self.0.clone() as usize
|
||||
}
|
||||
}
|
||||
impl Into<u32> for FontColor {
|
||||
fn into(self) -> u32 {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
impl Into<u16> for FontColor {
|
||||
fn into(self) -> u16 {
|
||||
self.0.clone() as u16
|
||||
}
|
||||
}
|
||||
impl Into<u64> for FontColor {
|
||||
fn into(self) -> u64 {
|
||||
self.0.clone() as u64
|
||||
}
|
||||
}
|
||||
|
||||
/// 彩色字符对象
|
||||
|
||||
#[derive(Clone, Debug, Copy)]
|
||||
pub struct TextuiCharChromatic {
|
||||
c: Option<char>,
|
||||
|
||||
// 前景色
|
||||
frcolor: FontColor, // rgb
|
||||
|
||||
// 背景色
|
||||
bkcolor: FontColor, // rgb
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TextuiBuf<'a>(&'a mut [u32]);
|
||||
|
||||
impl TextuiBuf<'_> {
|
||||
pub fn new(buf: &mut [u32]) -> TextuiBuf {
|
||||
TextuiBuf(buf)
|
||||
}
|
||||
pub fn put_color_in_pixel(&mut self, color: u32, index: usize) {
|
||||
let buf: &mut [u32] = self.0;
|
||||
buf[index] = color;
|
||||
}
|
||||
pub fn get_index_of_next_line(now_index: usize) -> usize {
|
||||
textui_framework().metadata.buf_info().buf_width() as usize + now_index
|
||||
}
|
||||
pub fn get_index_by_x_y(x: usize, y: usize) -> usize {
|
||||
textui_framework().metadata.buf_info().buf_width() as usize * y + x
|
||||
}
|
||||
pub fn get_start_index_by_lineid_lineindex(lineid: LineId, lineindex: LineIndex) -> usize {
|
||||
// x 左上角列像素点位置
|
||||
// y 左上角行像素点位置
|
||||
let index_x: u32 = lineindex.into();
|
||||
let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
|
||||
|
||||
let id_y: u32 = lineid.into();
|
||||
let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
|
||||
|
||||
TextuiBuf::get_index_by_x_y(x as usize, y as usize)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Font([u8; 16]);
|
||||
impl Font {
|
||||
#[inline]
|
||||
pub fn get_font(character: char) -> Font {
|
||||
let x = FONT_8x16.char_map(character);
|
||||
|
||||
let mut data = [0u8; 16];
|
||||
data.copy_from_slice(x);
|
||||
return Font(data);
|
||||
}
|
||||
pub fn is_frcolor(&self, height: usize, width: usize) -> bool {
|
||||
let w = self.0[height];
|
||||
let testbit = 1 << (8 - width);
|
||||
w & testbit != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl TextuiCharChromatic {
|
||||
pub fn new(c: Option<char>, frcolor: FontColor, bkcolor: FontColor) -> Self {
|
||||
TextuiCharChromatic {
|
||||
c,
|
||||
frcolor,
|
||||
bkcolor,
|
||||
}
|
||||
}
|
||||
|
||||
/// 将该字符对象输出到缓冲区
|
||||
/// ## 参数
|
||||
/// -line_id 要放入的真实行号
|
||||
/// -index 要放入的真实列号
|
||||
pub fn textui_refresh_character(
|
||||
&self,
|
||||
lineid: LineId,
|
||||
lineindex: LineIndex,
|
||||
) -> Result<i32, SystemError> {
|
||||
// 找到要渲染的字符的像素点数据
|
||||
|
||||
let font: Font = Font::get_font(self.c.unwrap_or(' '));
|
||||
|
||||
let mut count = TextuiBuf::get_start_index_by_lineid_lineindex(lineid, lineindex);
|
||||
|
||||
let mut buf = TextuiBuf::new(textui_framework().metadata.buf());
|
||||
// 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
|
||||
for i in 0..TEXTUI_CHAR_HEIGHT {
|
||||
let start = count;
|
||||
for j in 0..TEXTUI_CHAR_WIDTH {
|
||||
if font.is_frcolor(i as usize, j as usize) {
|
||||
// 字,显示前景色
|
||||
buf.put_color_in_pixel(self.frcolor.into(), count);
|
||||
} else {
|
||||
// 背景色
|
||||
buf.put_color_in_pixel(self.bkcolor.into(), count);
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
count = TextuiBuf::get_index_of_next_line(start);
|
||||
}
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
pub fn no_init_textui_render_chromatic(&self, lineid: LineId, lineindex: LineIndex) {
|
||||
// 找到要渲染的字符的像素点数据
|
||||
let font = Font::get_font(self.c.unwrap_or(' '));
|
||||
|
||||
// x 左上角列像素点位置
|
||||
// y 左上角行像素点位置
|
||||
let index_x: u32 = lineindex.into();
|
||||
let x: u32 = index_x * TEXTUI_CHAR_WIDTH;
|
||||
|
||||
let id_y: u32 = lineid.into();
|
||||
let y: u32 = id_y * TEXTUI_CHAR_HEIGHT;
|
||||
// 找到输入缓冲区的起始地址位置
|
||||
let fb = unsafe { video_frame_buffer_info.vaddr };
|
||||
|
||||
let mut testbit: u32; // 用来测试特定行的某列是背景还是字体本身
|
||||
|
||||
// 在缓冲区画出一个字体,每个字体有TEXTUI_CHAR_HEIGHT行,TEXTUI_CHAR_WIDTH列个像素点
|
||||
for i in 0..TEXTUI_CHAR_HEIGHT {
|
||||
// 计算出帧缓冲区每一行打印的起始位置的地址(起始位置+(y+i)*缓冲区的宽度+x)
|
||||
|
||||
let mut addr: *mut u32 = (fb
|
||||
+ unsafe { video_frame_buffer_info.width } as u64 * 4 * (y as u64 + i as u64)
|
||||
+ 4 * x as u64) as *mut u32;
|
||||
|
||||
testbit = 1 << (TEXTUI_CHAR_WIDTH + 1);
|
||||
|
||||
for _j in 0..TEXTUI_CHAR_WIDTH {
|
||||
//从左往右逐个测试相应位
|
||||
testbit >>= 1;
|
||||
if (font.0[i as usize] & testbit as u8) != 0 {
|
||||
unsafe { *addr = self.frcolor.into() }; // 字,显示前景色
|
||||
} else {
|
||||
unsafe { *addr = self.bkcolor.into() }; // 背景色
|
||||
}
|
||||
|
||||
unsafe {
|
||||
addr = (addr.offset(1)) as *mut u32;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 单色显示的虚拟行结构体
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TextuiVlineNormal {
|
||||
_characters: Vec<TextuiCharNormal>, // 字符对象数组
|
||||
_index: i16, // 当前操作的位置
|
||||
}
|
||||
/// 彩色显示的虚拟行结构体
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct TextuiVlineChromatic {
|
||||
chars: Vec<TextuiCharChromatic>, // 字符对象数组
|
||||
index: LineIndex, // 当前操作的位置
|
||||
}
|
||||
impl TextuiVlineChromatic {
|
||||
pub fn new(char_num: usize) -> Self {
|
||||
let mut r = TextuiVlineChromatic {
|
||||
chars: Vec::with_capacity(char_num),
|
||||
index: LineIndex::new(0),
|
||||
};
|
||||
|
||||
for _ in 0..char_num {
|
||||
r.chars.push(TextuiCharChromatic::new(
|
||||
None,
|
||||
FontColor::BLACK,
|
||||
FontColor::BLACK,
|
||||
));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TextuiVline {
|
||||
Chromatic(TextuiVlineChromatic),
|
||||
_Normal(TextuiVlineNormal),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct WindowId(u32);
|
||||
|
||||
impl WindowId {
|
||||
pub fn new() -> Self {
|
||||
static MAX_ID: AtomicU32 = AtomicU32::new(0);
|
||||
return WindowId(MAX_ID.fetch_add(1, Ordering::SeqCst));
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TextuiWindow {
|
||||
// 虚拟行是个循环表,头和尾相接
|
||||
id: WindowId,
|
||||
// 虚拟行总数
|
||||
vline_sum: i32,
|
||||
// 当前已经使用了的虚拟行总数(即在已经输入到缓冲区(之后显示在屏幕上)的虚拟行数量)
|
||||
vlines_used: i32,
|
||||
// 位于最顶上的那一个虚拟行的行号
|
||||
top_vline: LineId,
|
||||
// 储存虚拟行的数组
|
||||
vlines: Vec<TextuiVline>,
|
||||
// 正在操作的vline
|
||||
vline_operating: LineId,
|
||||
// 每行最大容纳的字符数
|
||||
chars_per_line: i32,
|
||||
// 窗口flag
|
||||
flags: WindowFlag,
|
||||
}
|
||||
|
||||
impl TextuiWindow {
|
||||
/// 使用参数初始化window对象
|
||||
/// ## 参数
|
||||
///
|
||||
/// -flags 标志位
|
||||
/// -vlines_num 虚拟行的总数
|
||||
/// -chars_num 每行最大的字符数
|
||||
|
||||
pub fn new(flags: WindowFlag, vlines_num: i32, chars_num: i32) -> Self {
|
||||
let mut initial_vlines = Vec::new();
|
||||
|
||||
for _ in 0..vlines_num {
|
||||
let vline = TextuiVlineChromatic::new(chars_num as usize);
|
||||
|
||||
initial_vlines.push(TextuiVline::Chromatic(vline));
|
||||
}
|
||||
TextuiWindow {
|
||||
id: WindowId::new(),
|
||||
flags,
|
||||
vline_sum: vlines_num,
|
||||
vlines_used: 1,
|
||||
top_vline: LineId::new(0),
|
||||
vlines: initial_vlines,
|
||||
vline_operating: LineId::new(0),
|
||||
chars_per_line: chars_num,
|
||||
}
|
||||
}
|
||||
|
||||
/// 刷新某个窗口的缓冲区的某个虚拟行的连续n个字符对象
|
||||
/// ## 参数
|
||||
/// - window 窗口结构体
|
||||
/// - vline_id 要刷新的虚拟行号
|
||||
/// - start 起始字符号
|
||||
/// - count 要刷新的字符数量
|
||||
|
||||
fn textui_refresh_characters(
|
||||
&mut self,
|
||||
vline_id: LineId,
|
||||
start: LineIndex,
|
||||
count: i32,
|
||||
) -> Result<(), SystemError> {
|
||||
let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
|
||||
|
||||
// 判断虚拟行参数是否合法
|
||||
if unlikely(
|
||||
!vline_id.check(self.vline_sum)
|
||||
|| (<LineIndex as Into<i32>>::into(start) + count) > self.chars_per_line,
|
||||
) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
// 计算虚拟行对应的真实行(即要渲染的行)
|
||||
let mut actual_line_id = vline_id - self.top_vline; //为正说明虚拟行不在真实行显示的区域上面
|
||||
|
||||
if <LineId as Into<i32>>::into(actual_line_id) < 0 {
|
||||
//真实行数小于虚拟行数,则需要加上真实行数的位置,以便正确计算真实行
|
||||
actual_line_id = actual_line_id + actual_line_sum;
|
||||
}
|
||||
|
||||
// 将此窗口的某个虚拟行的连续n个字符对象往缓存区写入
|
||||
if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
|
||||
let vline = &mut self.vlines[<LineId as Into<usize>>::into(vline_id)];
|
||||
let mut i = 0;
|
||||
let mut index = start;
|
||||
|
||||
while i < count {
|
||||
if let TextuiVline::Chromatic(vline) = vline {
|
||||
vline.chars[<LineIndex as Into<usize>>::into(index)]
|
||||
.textui_refresh_character(actual_line_id, index)?;
|
||||
|
||||
index = index + 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 重新渲染某个窗口的某个虚拟行
|
||||
/// ## 参数
|
||||
|
||||
/// - window 窗口结构体
|
||||
/// - vline_id 虚拟行号
|
||||
|
||||
fn textui_refresh_vline(&mut self, vline_id: LineId) -> Result<(), SystemError> {
|
||||
if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
|
||||
return self.textui_refresh_characters(
|
||||
vline_id,
|
||||
LineIndex::new(0),
|
||||
self.chars_per_line,
|
||||
);
|
||||
} else {
|
||||
//todo支持纯文本字符()
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新某个窗口的start 到start + count行(即将这些行输入到缓冲区)
|
||||
fn textui_refresh_vlines(&mut self, start: LineId, count: i32) -> Result<i32, SystemError> {
|
||||
let mut refresh_count = count;
|
||||
for i in <LineId as Into<i32>>::into(start)
|
||||
..(self.vline_sum).min(<LineId as Into<i32>>::into(start) + count)
|
||||
{
|
||||
self.textui_refresh_vline(LineId::new(i))?;
|
||||
refresh_count -= 1;
|
||||
}
|
||||
//因为虚拟行是循环表
|
||||
let mut refresh_start = 0;
|
||||
while refresh_count > 0 {
|
||||
self.textui_refresh_vline(LineId::new(refresh_start))?;
|
||||
refresh_start += 1;
|
||||
refresh_count -= 1;
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// 往某个窗口的缓冲区的某个虚拟行插入换行
|
||||
/// ## 参数
|
||||
/// - window 窗口结构体
|
||||
/// - vline_id 虚拟行号
|
||||
|
||||
fn textui_new_line(&mut self) -> Result<i32, SystemError> {
|
||||
// todo: 支持在两个虚拟行之间插入一个新行
|
||||
let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
|
||||
self.vline_operating = self.vline_operating + 1;
|
||||
//如果已经到了最大行数,则重新从0开始
|
||||
if !self.vline_operating.check(self.vline_sum) {
|
||||
self.vline_operating = LineId::new(0);
|
||||
}
|
||||
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
|
||||
{
|
||||
for i in 0..self.chars_per_line {
|
||||
if let Some(v_char) = vline.chars.get_mut(i as usize) {
|
||||
v_char.c = None;
|
||||
v_char.frcolor = FontColor::BLACK;
|
||||
v_char.bkcolor = FontColor::BLACK;
|
||||
}
|
||||
}
|
||||
vline.index = LineIndex::new(0);
|
||||
}
|
||||
// 当已经使用的虚拟行总数等于真实行总数时,说明窗口中已经显示的文本行数已经达到了窗口的最大容量。这时,如果继续在窗口中添加新的文本,就会导致文本溢出窗口而无法显示。因此,需要往下滚动屏幕来显示更多的文本。
|
||||
|
||||
if self.vlines_used == actual_line_sum {
|
||||
self.top_vline = self.top_vline + 1;
|
||||
|
||||
if !self.top_vline.check(self.vline_sum) {
|
||||
self.top_vline = LineId::new(0);
|
||||
}
|
||||
|
||||
// 刷新所有行
|
||||
self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
|
||||
} else {
|
||||
//换行说明上一行已经在缓冲区中,所以已经使用的虚拟行总数+1
|
||||
self.vlines_used += 1;
|
||||
}
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
/// 真正向窗口的缓冲区上输入字符的函数(位置为window.vline_operating,window.vline_operating.index)
|
||||
/// ## 参数
|
||||
/// - window
|
||||
/// - character
|
||||
|
||||
fn true_textui_putchar_window(
|
||||
&mut self,
|
||||
character: char,
|
||||
frcolor: FontColor,
|
||||
bkcolor: FontColor,
|
||||
) -> Result<(), SystemError> {
|
||||
// 启用彩色字符
|
||||
if self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
|
||||
let mut line_index = LineIndex::new(0); //操作的列号
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&mut (self.vlines[<LineId as Into<usize>>::into(self.vline_operating)])
|
||||
{
|
||||
let index = <LineIndex as Into<usize>>::into(vline.index);
|
||||
|
||||
if let Some(v_char) = vline.chars.get_mut(index) {
|
||||
v_char.c = Some(character);
|
||||
v_char.frcolor = frcolor;
|
||||
v_char.bkcolor = bkcolor;
|
||||
}
|
||||
line_index = vline.index;
|
||||
vline.index = vline.index + 1;
|
||||
}
|
||||
|
||||
self.textui_refresh_characters(self.vline_operating, line_index, 1)?;
|
||||
|
||||
// 加入光标后,因为会识别光标,所以需超过该行最大字符数才能创建新行
|
||||
if !line_index.check(self.chars_per_line - 1) {
|
||||
self.textui_new_line()?;
|
||||
}
|
||||
} else {
|
||||
// todo: 支持纯文本字符
|
||||
todo!();
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
/// 根据输入的一个字符在窗口上输出
|
||||
/// ## 参数
|
||||
|
||||
/// - window 窗口
|
||||
/// - character 字符
|
||||
/// - FRcolor 前景色(RGB)
|
||||
/// - BKcolor 背景色(RGB)
|
||||
|
||||
fn textui_putchar_window(
|
||||
&mut self,
|
||||
character: char,
|
||||
frcolor: FontColor,
|
||||
bkcolor: FontColor,
|
||||
is_enable_window: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
let actual_line_sum = textui_framework().actual_line.load(Ordering::SeqCst);
|
||||
|
||||
//字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
|
||||
if unlikely(character == '\0') {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if unlikely(character == '\r') {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// 暂不支持纯文本窗口
|
||||
if !self.flags.contains(WindowFlag::TEXTUI_CHROMATIC) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
//进行换行操作
|
||||
if character == '\n' {
|
||||
// 换行时还需要输出\r
|
||||
c_uart_send(UartPort::COM1.to_u16(), b'\r');
|
||||
if is_enable_window == true {
|
||||
self.textui_new_line()?;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// 输出制表符
|
||||
else if character == '\t' {
|
||||
if is_enable_window == true {
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
|
||||
{
|
||||
//打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
|
||||
let mut space_to_print = 8 - <LineIndex as Into<usize>>::into(vline.index) % 8;
|
||||
while space_to_print > 0 {
|
||||
self.true_textui_putchar_window(' ', frcolor, bkcolor)?;
|
||||
space_to_print -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
|
||||
else if character == '\x08' {
|
||||
if is_enable_window == true {
|
||||
let mut tmp = LineIndex(0);
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
|
||||
{
|
||||
vline.index = vline.index - 1;
|
||||
tmp = vline.index;
|
||||
}
|
||||
if <LineIndex as Into<i32>>::into(tmp) >= 0 {
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
|
||||
{
|
||||
if let Some(v_char) =
|
||||
vline.chars.get_mut(<LineIndex as Into<usize>>::into(tmp))
|
||||
{
|
||||
v_char.c = Some(' ');
|
||||
|
||||
v_char.bkcolor = bkcolor;
|
||||
}
|
||||
}
|
||||
return self.textui_refresh_characters(self.vline_operating, tmp, 1);
|
||||
}
|
||||
// 需要向上缩一行
|
||||
if <LineIndex as Into<i32>>::into(tmp) < 0 {
|
||||
// 当前行为空,需要重新刷新
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&mut self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
|
||||
{
|
||||
vline.index = LineIndex::new(0);
|
||||
for i in 0..self.chars_per_line {
|
||||
if let Some(v_char) = vline.chars.get_mut(i as usize) {
|
||||
v_char.c = None;
|
||||
v_char.frcolor = FontColor::BLACK;
|
||||
v_char.bkcolor = FontColor::BLACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 上缩一行
|
||||
self.vline_operating = self.vline_operating - 1;
|
||||
if self.vline_operating.data() < 0 {
|
||||
self.vline_operating = LineId(self.vline_sum - 1);
|
||||
}
|
||||
|
||||
// 考虑是否向上滚动(在top_vline上退格)
|
||||
if self.vlines_used > actual_line_sum {
|
||||
self.top_vline = self.top_vline - 1;
|
||||
if <LineId as Into<i32>>::into(self.top_vline) < 0 {
|
||||
self.top_vline = LineId(self.vline_sum - 1);
|
||||
}
|
||||
}
|
||||
//因为上缩一行所以显示在屏幕中的虚拟行少一
|
||||
self.vlines_used -= 1;
|
||||
self.textui_refresh_vlines(self.top_vline, actual_line_sum)?;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 输出其他字符
|
||||
|
||||
c_uart_send(UartPort::COM1.to_u16(), character as u8);
|
||||
|
||||
if is_enable_window == true {
|
||||
if let TextuiVline::Chromatic(vline) =
|
||||
&self.vlines[<LineId as Into<usize>>::into(self.vline_operating)]
|
||||
{
|
||||
if !vline.index.check(self.chars_per_line) {
|
||||
self.textui_new_line()?;
|
||||
}
|
||||
|
||||
return self.true_textui_putchar_window(character, frcolor, bkcolor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
impl Default for TextuiWindow {
|
||||
fn default() -> Self {
|
||||
TextuiWindow {
|
||||
id: WindowId(0),
|
||||
flags: WindowFlag::TEXTUI_CHROMATIC,
|
||||
vline_sum: 0,
|
||||
vlines_used: 1,
|
||||
top_vline: LineId::new(0),
|
||||
vlines: Vec::new(),
|
||||
vline_operating: LineId::new(0),
|
||||
chars_per_line: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug)]
|
||||
pub struct TextUiFramework {
|
||||
metadata: ScmUiFrameworkMetadata,
|
||||
window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
|
||||
actual_line: AtomicI32, // 真实行的数量(textui的帧缓冲区能容纳的内容的行数)
|
||||
current_window: Arc<SpinLock<TextuiWindow>>, // 当前的主窗口
|
||||
default_window: Arc<SpinLock<TextuiWindow>>, // 默认print到的窗口
|
||||
}
|
||||
|
||||
impl TextUiFramework {
|
||||
pub fn new(
|
||||
metadata: ScmUiFrameworkMetadata,
|
||||
window_list: Arc<SpinLock<LinkedList<Arc<SpinLock<TextuiWindow>>>>>,
|
||||
current_window: Arc<SpinLock<TextuiWindow>>,
|
||||
default_window: Arc<SpinLock<TextuiWindow>>,
|
||||
) -> Self {
|
||||
let actual_line =
|
||||
AtomicI32::new((&metadata.buf_info().buf_height() / TEXTUI_CHAR_HEIGHT) as i32);
|
||||
let inner = TextUiFramework {
|
||||
metadata,
|
||||
window_list,
|
||||
actual_line,
|
||||
current_window,
|
||||
default_window,
|
||||
};
|
||||
return inner;
|
||||
}
|
||||
}
|
||||
|
||||
impl ScmUiFramework for &mut TextUiFramework {
|
||||
// 安装ui框架的回调函数
|
||||
fn install(&self) -> Result<i32, SystemError> {
|
||||
c_uart_send_str(
|
||||
UartPort::COM1.to_u16(),
|
||||
"\ntextui_install_handler\n\0".as_ptr(),
|
||||
);
|
||||
return Ok(0);
|
||||
}
|
||||
// 卸载ui框架的回调函数
|
||||
fn uninstall(&self) -> Result<i32, SystemError> {
|
||||
return Ok(0);
|
||||
}
|
||||
// 启用ui框架的回调函数
|
||||
fn enable(&self) -> Result<i32, SystemError> {
|
||||
ENABLE_PUT_TO_WINDOW.store(true, Ordering::SeqCst);
|
||||
return Ok(0);
|
||||
}
|
||||
// 禁用ui框架的回调函数
|
||||
fn disable(&self) -> Result<i32, SystemError> {
|
||||
ENABLE_PUT_TO_WINDOW.store(false, Ordering::SeqCst);
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
// 改变ui框架的帧缓冲区的回调函数
|
||||
fn change(&self, buf_info: ScmBufferInfo) -> Result<i32, SystemError> {
|
||||
let src_buf = textui_framework().metadata.buf();
|
||||
textui_framework().metadata.set_buf_info(buf_info);
|
||||
let dst_buf = textui_framework().metadata.buf();
|
||||
dst_buf.copy_from_slice(src_buf);
|
||||
return Ok(0);
|
||||
}
|
||||
/// 获取ScmUiFramework的元数据
|
||||
/// ## 返回值
|
||||
///
|
||||
/// -成功:Ok(ScmUiFramework的元数据)
|
||||
/// -失败:Err(错误码)
|
||||
fn metadata(&self) -> Result<ScmUiFrameworkMetadata, SystemError> {
|
||||
let metadata = self.metadata.clone();
|
||||
|
||||
return Ok(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
/// Mapping from characters to glyph indices.
|
||||
pub trait GlyphMapping: Sync {
|
||||
/// Maps a character to a glyph index.
|
||||
///
|
||||
/// If `c` isn't included in the font the index of a suitable replacement glyph is returned.
|
||||
fn index(&self, c: char) -> usize;
|
||||
}
|
||||
|
||||
impl<F> GlyphMapping for F
|
||||
where
|
||||
F: Sync + Fn(char) -> usize,
|
||||
{
|
||||
fn index(&self, c: char) -> usize {
|
||||
self(c)
|
||||
}
|
||||
}
|
||||
|
||||
/// 在默认窗口上输出一个字符
|
||||
/// ## 参数
|
||||
/// - character 字符
|
||||
/// - FRcolor 前景色(RGB)
|
||||
/// - BKcolor 背景色(RGB)
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_textui_putchar(character: u8, fr_color: u32, bk_color: u32) -> i32 {
|
||||
return textui_putchar(
|
||||
character as char,
|
||||
FontColor::from(fr_color),
|
||||
FontColor::from(bk_color),
|
||||
)
|
||||
.map(|_| 0)
|
||||
.unwrap_or_else(|e| e.to_posix_errno());
|
||||
}
|
||||
|
||||
pub fn textui_putchar(
|
||||
character: char,
|
||||
fr_color: FontColor,
|
||||
bk_color: FontColor,
|
||||
) -> Result<(), SystemError> {
|
||||
if unsafe { TEXTUI_IS_INIT } {
|
||||
return textui_framework()
|
||||
.current_window
|
||||
.lock()
|
||||
.textui_putchar_window(
|
||||
character,
|
||||
fr_color,
|
||||
bk_color,
|
||||
ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
|
||||
);
|
||||
} else {
|
||||
//未初始化暴力输出
|
||||
return no_init_textui_putchar_window(
|
||||
character,
|
||||
fr_color,
|
||||
bk_color,
|
||||
ENABLE_PUT_TO_WINDOW.load(Ordering::SeqCst),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 初始化text ui框架
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn rs_textui_init() -> i32 {
|
||||
let r = textui_init().unwrap_or_else(|e| e.to_posix_errno());
|
||||
if r.is_negative() {
|
||||
c_uart_send_str(UartPort::COM1.to_u16(), "textui init failed.\n\0".as_ptr());
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
fn textui_init() -> Result<i32, SystemError> {
|
||||
unsafe { textui_framwork_init() };
|
||||
let textui_framework = textui_framework();
|
||||
|
||||
unsafe { TEXTUI_IS_INIT = true };
|
||||
|
||||
scm_register(Arc::new(textui_framework))?;
|
||||
|
||||
c_uart_send_str(
|
||||
UartPort::COM1.to_u16(),
|
||||
"\ntext ui initialized\n\0".as_ptr(),
|
||||
);
|
||||
|
||||
return Ok(0);
|
||||
}
|
125
kernel/src/libs/lib_ui/textui_no_alloc.rs
Normal file
125
kernel/src/libs/lib_ui/textui_no_alloc.rs
Normal file
@ -0,0 +1,125 @@
|
||||
use core::{
|
||||
intrinsics::unlikely,
|
||||
sync::atomic::{AtomicI32, Ordering},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
driver::uart::uart::{c_uart_send, UartPort},
|
||||
include::bindings::bindings::video_frame_buffer_info,
|
||||
syscall::SystemError,
|
||||
};
|
||||
|
||||
use super::textui::{
|
||||
FontColor, LineId, LineIndex, TextuiCharChromatic, TEXTUI_CHAR_HEIGHT, TEXTUI_CHAR_WIDTH,
|
||||
};
|
||||
|
||||
pub static TRUE_LINE_NUM: AtomicI32 = AtomicI32::new(0);
|
||||
pub static CHAR_PER_LINE: AtomicI32 = AtomicI32::new(0);
|
||||
/// textui 未初始化时直接向缓冲区写,不使用虚拟行
|
||||
pub static NO_ALLOC_OPERATIONS_LINE: AtomicI32 = AtomicI32::new(0);
|
||||
pub static NO_ALLOC_OPERATIONS_INDEX: AtomicI32 = AtomicI32::new(0);
|
||||
|
||||
/// 当系统刚启动的时候,由于内存管理未初始化,而texiui需要动态内存分配。因此只能暂时暴力往屏幕(video_frame_buffer_info)输出信息
|
||||
pub fn textui_init_no_alloc() {
|
||||
TRUE_LINE_NUM.store(
|
||||
unsafe { (video_frame_buffer_info.height / TEXTUI_CHAR_HEIGHT) as i32 },
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
|
||||
CHAR_PER_LINE.store(
|
||||
unsafe { (video_frame_buffer_info.width / TEXTUI_CHAR_WIDTH) as i32 },
|
||||
Ordering::SeqCst,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn no_init_textui_putchar_window(
|
||||
character: char,
|
||||
frcolor: FontColor,
|
||||
bkcolor: FontColor,
|
||||
is_put_to_window: bool,
|
||||
) -> Result<(), SystemError> {
|
||||
if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) > TRUE_LINE_NUM.load(Ordering::SeqCst) {
|
||||
NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst);
|
||||
}
|
||||
//字符'\0'代表ASCII码表中的空字符,表示字符串的结尾
|
||||
if unlikely(character == '\0') {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
c_uart_send(UartPort::COM1.to_u16(), character as u8);
|
||||
|
||||
// 进行换行操作
|
||||
if unlikely(character == '\n') {
|
||||
// 换行时还需要输出\r
|
||||
c_uart_send(UartPort::COM1.to_u16(), b'\r');
|
||||
if is_put_to_window == true {
|
||||
NO_ALLOC_OPERATIONS_LINE.fetch_add(1, Ordering::SeqCst);
|
||||
NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// 输出制表符
|
||||
else if character == '\t' {
|
||||
if is_put_to_window == true {
|
||||
let char = TextuiCharChromatic::new(Some(' '), frcolor, bkcolor);
|
||||
|
||||
//打印的空格数(注意将每行分成一个个表格,每个表格为8个字符)
|
||||
let mut space_to_print = 8 - NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst) % 8;
|
||||
while space_to_print > 0 {
|
||||
char.no_init_textui_render_chromatic(
|
||||
LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
|
||||
LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
|
||||
);
|
||||
NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
|
||||
space_to_print -= 1;
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
// 字符 '\x08' 代表 ASCII 码中的退格字符。它在输出中的作用是将光标向左移动一个位置,并在该位置上输出后续的字符,从而实现字符的删除或替换。
|
||||
else if character == '\x08' {
|
||||
if is_put_to_window == true {
|
||||
NO_ALLOC_OPERATIONS_INDEX.fetch_sub(1, Ordering::SeqCst);
|
||||
let op_char = NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst);
|
||||
if op_char >= 0 {
|
||||
let char = TextuiCharChromatic::new(Some(' '), frcolor, bkcolor);
|
||||
char.no_init_textui_render_chromatic(
|
||||
LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
|
||||
LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
|
||||
);
|
||||
|
||||
NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
// 需要向上缩一行
|
||||
if op_char < 0 {
|
||||
// 上缩一行
|
||||
NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
|
||||
NO_ALLOC_OPERATIONS_LINE.fetch_sub(1, Ordering::SeqCst);
|
||||
|
||||
if NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst) < 0 {
|
||||
NO_ALLOC_OPERATIONS_LINE.store(0, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if is_put_to_window == true {
|
||||
// 输出其他字符
|
||||
let char = TextuiCharChromatic::new(Some(character), frcolor, bkcolor);
|
||||
|
||||
if NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)
|
||||
== CHAR_PER_LINE.load(Ordering::SeqCst)
|
||||
{
|
||||
NO_ALLOC_OPERATIONS_INDEX.store(0, Ordering::SeqCst);
|
||||
NO_ALLOC_OPERATIONS_LINE.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
char.no_init_textui_render_chromatic(
|
||||
LineId::new(NO_ALLOC_OPERATIONS_LINE.load(Ordering::SeqCst)),
|
||||
LineIndex::new(NO_ALLOC_OPERATIONS_INDEX.load(Ordering::SeqCst)),
|
||||
);
|
||||
|
||||
NO_ALLOC_OPERATIONS_INDEX.fetch_add(1, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
@ -7,6 +7,7 @@ pub mod ffi_convert;
|
||||
pub mod int_like;
|
||||
pub mod keyboard_parser;
|
||||
pub mod lazy_init;
|
||||
pub mod lib_ui;
|
||||
pub mod list;
|
||||
pub mod lockref;
|
||||
pub mod mutex;
|
||||
|
@ -5,7 +5,7 @@
|
||||
#include <common/printk.h>
|
||||
|
||||
#include <common/spinlock.h>
|
||||
#include <libs/libUI/textui.h>
|
||||
#include <libs/lib_ui/textui.h>
|
||||
#include <mm/mm.h>
|
||||
|
||||
#include <common/math.h>
|
||||
@ -610,7 +610,7 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
|
||||
{
|
||||
current = *(buf + i);
|
||||
// 输出
|
||||
textui_putchar(current, FRcolor, BKcolor);
|
||||
rs_textui_putchar(current, FRcolor, BKcolor);
|
||||
}
|
||||
io_mfence();
|
||||
spin_unlock_irqrestore(&__printk_lock, rflags);
|
||||
|
@ -1,35 +1,6 @@
|
||||
#![allow(unused)]
|
||||
use crate::{
|
||||
driver::uart::uart::c_uart_send_str,
|
||||
include::bindings::bindings::{printk_color, BLACK, WHITE},
|
||||
};
|
||||
use ::core::ffi::c_char;
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
fmt::{self, Write},
|
||||
intrinsics::{likely, unlikely},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
use core::fmt::{self, Write};
|
||||
|
||||
// ====== 定义颜色 ======
|
||||
/// 白色
|
||||
pub const COLOR_WHITE: u32 = 0x00ffffff;
|
||||
/// 黑色
|
||||
pub const COLOR_BLACK: u32 = 0x00000000;
|
||||
/// 红色
|
||||
pub const COLOR_RED: u32 = 0x00ff0000;
|
||||
/// 橙色
|
||||
pub const COLOR_ORANGE: u32 = 0x00ff8000;
|
||||
/// 黄色
|
||||
pub const COLOR_YELLOW: u32 = 0x00ffff00;
|
||||
/// 绿色
|
||||
pub const COLOR_GREEN: u32 = 0x0000ff00;
|
||||
/// 蓝色
|
||||
pub const COLOR_BLUE: u32 = 0x000000ff;
|
||||
/// 靛色
|
||||
pub const COLOR_INDIGO: u32 = 0x0000ffff;
|
||||
/// 紫色
|
||||
pub const COLOR_PURPLE: u32 = 0x008000ff;
|
||||
use super::lib_ui::textui::{textui_putchar, FontColor};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! print {
|
||||
@ -74,7 +45,7 @@ macro_rules! kinfo {
|
||||
#[macro_export]
|
||||
macro_rules! kwarn {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_YELLOW, $crate::libs::printk::COLOR_BLACK, "[ WARN ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::YELLOW, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ WARN ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||
}
|
||||
}
|
||||
@ -82,7 +53,7 @@ macro_rules! kwarn {
|
||||
#[macro_export]
|
||||
macro_rules! kerror {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ ERROR ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ ERROR ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||
}
|
||||
}
|
||||
@ -90,121 +61,30 @@ macro_rules! kerror {
|
||||
#[macro_export]
|
||||
macro_rules! kBUG {
|
||||
($($arg:tt)*) => {
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ BUG ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ BUG ] ");
|
||||
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrintkWriter;
|
||||
|
||||
/// 由于内存管理初始化完成之前,无法使用动态内存分配,所以需要在内存管理初始化完成之后才能使用动态内存分配
|
||||
static ALLOW_ALLOC_ATOMIC: AtomicBool = AtomicBool::new(false);
|
||||
static mut ALLOW_ALLOC_BOOL: bool = false;
|
||||
|
||||
impl PrintkWriter {
|
||||
#[inline]
|
||||
pub fn __write_fmt(&mut self, args: fmt::Arguments) {
|
||||
self.write_fmt(args);
|
||||
self.write_fmt(args).ok();
|
||||
}
|
||||
|
||||
/// 调用C语言编写的printk_color,并输出白底黑字(暂时只支持ascii字符)
|
||||
/// 并输出白底黑字
|
||||
/// @param str: 要写入的字符
|
||||
pub fn __write_string(&mut self, s: &str) {
|
||||
if unlikely(!self.allow_alloc()) {
|
||||
self.__write_string_on_stack(s);
|
||||
return;
|
||||
}
|
||||
let str_to_print = self.__utf8_to_ascii(s);
|
||||
unsafe {
|
||||
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
|
||||
for c in s.chars() {
|
||||
textui_putchar(c, FontColor::WHITE, FontColor::BLACK).ok();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
|
||||
if unlikely(!self.allow_alloc()) {
|
||||
self.__write_string_on_stack(s);
|
||||
return;
|
||||
}
|
||||
|
||||
let str_to_print = self.__utf8_to_ascii(s);
|
||||
unsafe {
|
||||
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn allow_alloc(&self) -> bool {
|
||||
// 由于allow_alloc只可能由false变为true
|
||||
// 因此采用两种方式读取它,一种是原子操作,一种是普通的bool,以优化性能。
|
||||
if likely(unsafe { ALLOW_ALLOC_BOOL }) {
|
||||
return true;
|
||||
} else {
|
||||
return ALLOW_ALLOC_ATOMIC.load(Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
/// 允许动态内存分配
|
||||
pub fn enable_alloc(&self) {
|
||||
ALLOW_ALLOC_ATOMIC.store(true, Ordering::SeqCst);
|
||||
unsafe {
|
||||
ALLOW_ALLOC_BOOL = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// 将s这个utf8字符串,转换为ascii字符串
|
||||
/// @param s 待转换的utf8字符串
|
||||
/// @return Vec<u8> 转换结束后的Ascii字符串
|
||||
pub fn __utf8_to_ascii(&self, s: &str) -> Vec<u8> {
|
||||
let mut ascii_str: Vec<u8> = Vec::with_capacity(s.len() + 1);
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
0..=127 => {
|
||||
ascii_str.push(byte);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
ascii_str.push(b'\0');
|
||||
return ascii_str;
|
||||
}
|
||||
|
||||
fn __write_string_on_stack(&self, s: &str) {
|
||||
let s_len = s.len();
|
||||
assert!(s_len < 1024, "s_len is too long");
|
||||
let mut str_to_print: [u8; 1024] = [0; 1024];
|
||||
let mut i = 0;
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
0..=127 => {
|
||||
str_to_print[i] = byte;
|
||||
i += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
str_to_print[i] = b'\0';
|
||||
unsafe {
|
||||
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
|
||||
}
|
||||
}
|
||||
|
||||
fn __write_string_color_on_stack(&self, fr_color: u32, bk_color: u32, s: &str) {
|
||||
let s_len = s.len();
|
||||
assert!(s_len < 1024, "s_len is too long");
|
||||
let mut str_to_print: [u8; 1024] = [0; 1024];
|
||||
let mut i = 0;
|
||||
for byte in s.bytes() {
|
||||
match byte {
|
||||
0..=127 => {
|
||||
str_to_print[i] = byte;
|
||||
i += 1;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
str_to_print[i] = b'\0';
|
||||
unsafe {
|
||||
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
|
||||
pub fn __write_string_color(&self, fr_color: FontColor, bk_color: FontColor, s: &str) {
|
||||
for c in s.chars() {
|
||||
textui_putchar(c, fr_color, bk_color).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -219,6 +99,5 @@ impl fmt::Write for PrintkWriter {
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn __printk(args: fmt::Arguments) {
|
||||
use fmt::Write;
|
||||
PrintkWriter.write_fmt(args).unwrap();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::arch::asm::irqflags::{local_irq_restore, local_irq_save};
|
||||
use crate::arch::interrupt::{cli, sti};
|
||||
|
||||
use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
|
||||
use crate::process::preempt::{preempt_disable, preempt_enable};
|
||||
use crate::syscall::SystemError;
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "smp/smp.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include <exception/softirq.h>
|
||||
#include <libs/libUI/screen_manager.h>
|
||||
#include <libs/libUI/textui.h>
|
||||
#include <libs/lib_ui/screen_manager.h>
|
||||
#include <libs/lib_ui/textui.h>
|
||||
#include <sched/sched.h>
|
||||
#include <smp/ipi.h>
|
||||
|
||||
@ -71,10 +71,10 @@ void reload_idt()
|
||||
void system_initialize()
|
||||
{
|
||||
c_uart_init(COM1, 115200);
|
||||
|
||||
video_init();
|
||||
|
||||
scm_init();
|
||||
textui_init();
|
||||
kinfo("Kernel Starting...");
|
||||
// 重新加载gdt和idt
|
||||
ul tss_item_addr = (ul)phys_2_virt(0x7c00);
|
||||
|
||||
@ -92,7 +92,6 @@ void system_initialize()
|
||||
|
||||
// 初始化中断描述符表
|
||||
sys_vector_init();
|
||||
|
||||
// 初始化内存管理单元
|
||||
// mm_init();
|
||||
rs_mm_init();
|
||||
@ -101,8 +100,12 @@ void system_initialize()
|
||||
// 原因是,系统启动初期,framebuffer被映射到48M地址处,
|
||||
// mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃
|
||||
// 对显示模块进行低级初始化,不启用double buffer
|
||||
scm_reinit();
|
||||
|
||||
io_mfence();
|
||||
scm_reinit();
|
||||
rs_textui_init();
|
||||
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
|
||||
io_mfence();
|
||||
// =========== 重新设置initial_tss[0]的ist
|
||||
uchar *ptr = (uchar *)kzalloc(STACK_SIZE, 0) + STACK_SIZE;
|
||||
((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0;
|
||||
|
@ -1,6 +1,7 @@
|
||||
//! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能
|
||||
//!
|
||||
//! 这里假设在内核引导文件中,已经填写了前100M的内存映射关系,因此这里不需要任何动态分配。
|
||||
//! 这里假设在内核引导文件中,已经填写了前100M的页表,其中,前50M是真实映射到内存的,后面的仅仅创建了页表,表项全部为0。
|
||||
//! 因此这里映射内存不需要任何动态分配。
|
||||
//!
|
||||
//! 映射关系为:
|
||||
//!
|
||||
|
@ -1,4 +1,3 @@
|
||||
target remote localhost:1234
|
||||
file bin/kernel/kernel.elf
|
||||
set follow-fork-mode child
|
||||
b Start_Kernel
|
@ -506,6 +506,7 @@ int shell_cmd_exec(int argc, char **argv)
|
||||
int path_len = 0;
|
||||
char *file_path = get_target_filepath(argv[1], &path_len);
|
||||
// printf("before execv, path=%s, argc=%d\n", file_path, argc);
|
||||
|
||||
execv(file_path, argv);
|
||||
// printf("after execv, path=%s, argc=%d\n", file_path, argc);
|
||||
free(argv);
|
||||
@ -520,13 +521,14 @@ int shell_cmd_exec(int argc, char **argv)
|
||||
waitpid(pid, &retval, 0);
|
||||
else
|
||||
printf("[1] %d\n", pid); // 输出子进程的pid
|
||||
|
||||
|
||||
free(argv);
|
||||
}
|
||||
}
|
||||
|
||||
int shell_cmd_about(int argc, char **argv)
|
||||
{
|
||||
|
||||
if (argv != NULL)
|
||||
free(argv);
|
||||
int aac = 0;
|
||||
|
@ -79,8 +79,12 @@ void main_loop(int kb_fd)
|
||||
strcpy(command_origin, input_buffer);
|
||||
int cmd_num = parse_command(input_buffer, &argc, &argv);
|
||||
printf("\n");
|
||||
|
||||
|
||||
if (cmd_num >= 0)
|
||||
shell_run_built_in_command(cmd_num, argc, argv);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
printf("\n");
|
||||
|
@ -155,6 +155,7 @@ int execv(const char *path, char *const argv[])
|
||||
errno = -ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
|
||||
if (retval != 0)
|
||||
return -1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user