mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 19:36:47 +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",
|
"stdbool.h": "c",
|
||||||
"printk.h": "c",
|
"printk.h": "c",
|
||||||
"stdarg.h": "c",
|
"stdarg.h": "c",
|
||||||
"font.h": "c",
|
|
||||||
"trap.h": "c",
|
"trap.h": "c",
|
||||||
"gate.h": "c",
|
"gate.h": "c",
|
||||||
"process.h": "c",
|
"process.h": "c",
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
kernel/debug/index
|
kernel/debug/index
|
||||||
kernel/ktest/index
|
kernel/ktest/index
|
||||||
kernel/cpu_arch/index
|
kernel/cpu_arch/index
|
||||||
|
kernel/libs/index
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
.. 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::driver::uart::uart::c_uart_send_str;
|
||||||
use crate::include::bindings::bindings::{
|
use crate::include::bindings::bindings::{
|
||||||
disable_textui, enable_textui, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
||||||
video_reinitialize,
|
|
||||||
};
|
};
|
||||||
use crate::libs::align::page_align_up;
|
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::printk::PrintkWriter;
|
||||||
use crate::libs::spinlock::SpinLock;
|
use crate::libs::spinlock::SpinLock;
|
||||||
|
|
||||||
@ -315,8 +315,6 @@ pub fn mm_init() {
|
|||||||
unsafe { allocator_init() };
|
unsafe { allocator_init() };
|
||||||
// enable mmio
|
// enable mmio
|
||||||
mmio_init();
|
mmio_init();
|
||||||
// 启用printk的alloc选项
|
|
||||||
PrintkWriter.enable_alloc();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn allocator_init() {
|
unsafe fn allocator_init() {
|
||||||
@ -396,9 +394,8 @@ unsafe fn allocator_init() {
|
|||||||
unsafe { set_inner_allocator(buddy_allocator) };
|
unsafe { set_inner_allocator(buddy_allocator) };
|
||||||
kinfo!("Successfully initialized buddy allocator");
|
kinfo!("Successfully initialized buddy allocator");
|
||||||
// 关闭显示输出
|
// 关闭显示输出
|
||||||
unsafe {
|
scm_disable_put_to_window();
|
||||||
disable_textui();
|
|
||||||
}
|
|
||||||
// make the new page table current
|
// make the new page table current
|
||||||
{
|
{
|
||||||
let mut binding = INNER_ALLOCATOR.lock();
|
let mut binding = INNER_ALLOCATOR.lock();
|
||||||
@ -416,16 +413,6 @@ unsafe fn allocator_init() {
|
|||||||
kdebug!("New page table enabled");
|
kdebug!("New page table enabled");
|
||||||
}
|
}
|
||||||
kdebug!("Successfully enabled new page table");
|
kdebug!("Successfully enabled new page table");
|
||||||
// 重置显示输出目标
|
|
||||||
unsafe {
|
|
||||||
video_reinitialize(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开显示输出
|
|
||||||
unsafe {
|
|
||||||
enable_textui();
|
|
||||||
}
|
|
||||||
kdebug!("Text UI enabled");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
#include <arch/x86_64/include/asm/cmpxchg.h>
|
#include <arch/x86_64/include/asm/cmpxchg.h>
|
||||||
|
|
||||||
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
|
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
|
||||||
#define atomic_set(atomic,val) (((atomic)->value) = (val)) // 设置原子变量的初始值
|
#define atomic_set(atomic, val) (((atomic)->value) = (val)) // 设置原子变量的初始值
|
||||||
|
|
||||||
typedef struct
|
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 is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
|
||||||
|
|
||||||
// 字体颜色的宏定义
|
// 字体颜色的宏定义
|
||||||
#define WHITE 0x00ffffff //白
|
#define WHITE 0x00ffffff // 白
|
||||||
#define BLACK 0x00000000 //黑
|
#define BLACK 0x00000000 // 黑
|
||||||
#define RED 0x00ff0000 //红
|
#define RED 0x00ff0000 // 红
|
||||||
#define ORANGE 0x00ff8000 //橙
|
#define ORANGE 0x00ff8000 // 橙
|
||||||
#define YELLOW 0x00ffff00 //黄
|
#define YELLOW 0x00ffff00 // 黄
|
||||||
#define GREEN 0x0000ff00 //绿
|
#define GREEN 0x0000ff00 // 绿
|
||||||
#define BLUE 0x000000ff //蓝
|
#define BLUE 0x000000ff // 蓝
|
||||||
#define INDIGO 0x0000ffff //靛
|
#define INDIGO 0x0000ffff // 靛
|
||||||
#define PURPLE 0x008000ff //紫
|
#define PURPLE 0x008000ff // 紫
|
||||||
|
|
||||||
// 异常的宏定义
|
// 异常的宏定义
|
||||||
#define EPOS_OVERFLOW 1 // 坐标溢出
|
#define EPOS_OVERFLOW 1 // 坐标溢出
|
||||||
#define EFB_MISMATCH 2 // 帧缓冲区与指定的屏幕大小不匹配
|
#define EFB_MISMATCH 2 // 帧缓冲区与指定的屏幕大小不匹配
|
||||||
#define EUNSUPPORTED 3 // 当前操作暂不被支持
|
#define EUNSUPPORTED 3 // 当前操作暂不被支持
|
||||||
|
|
||||||
#include "font.h"
|
|
||||||
#include "glib.h"
|
#include "glib.h"
|
||||||
#include <libs/libUI/screen_manager.h>
|
#include <libs/lib_ui/screen_manager.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap(8*16大小) ps:位于font.h中
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中
|
* @brief 将字符串按照fmt和args中的内容进行格式化,然后保存到buf中
|
||||||
*
|
*
|
||||||
|
@ -326,7 +326,7 @@ void apic_local_apic_init()
|
|||||||
|
|
||||||
// 检测是否成功启用xAPIC和x2APIC
|
// 检测是否成功启用xAPIC和x2APIC
|
||||||
if ((eax & 0xc00) == 0xc00)
|
if ((eax & 0xc00) == 0xc00)
|
||||||
kinfo("xAPIC & x2APIC enabled!");
|
kinfo("xAPIC & x2APIC enabled!\n");
|
||||||
else if ((eax & 0x800) == 0x800)
|
else if ((eax & 0x800) == 0x800)
|
||||||
kinfo("Only xAPIC enabled!");
|
kinfo("Only xAPIC enabled!");
|
||||||
else
|
else
|
||||||
|
@ -9,9 +9,11 @@ use crate::{
|
|||||||
devfs::{devfs_register, DevFS, DeviceINode},
|
devfs::{devfs_register, DevFS, DeviceINode},
|
||||||
vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
|
vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
|
||||||
},
|
},
|
||||||
include::bindings::bindings::{textui_putchar, BLACK, WHITE},
|
|
||||||
kerror,
|
kerror,
|
||||||
libs::rwlock::RwLock,
|
libs::{
|
||||||
|
lib_ui::textui::{textui_putchar, FontColor},
|
||||||
|
rwlock::RwLock,
|
||||||
|
},
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -255,10 +257,9 @@ impl IndexNode for TtyDevice {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// 输出到屏幕
|
// 输出到屏幕
|
||||||
unsafe {
|
|
||||||
for x in buf {
|
for x in buf {
|
||||||
textui_putchar(x as u16, WHITE, BLACK);
|
textui_putchar(x as char, FontColor::WHITE, FontColor::BLACK).ok();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -17,10 +17,10 @@ extern void rs_register_softirq_video();
|
|||||||
|
|
||||||
uint64_t video_refresh_expire_jiffies = 0;
|
uint64_t video_refresh_expire_jiffies = 0;
|
||||||
uint64_t video_last_refresh_pid = -1;
|
uint64_t video_last_refresh_pid = -1;
|
||||||
|
|
||||||
struct scm_buffer_info_t video_frame_buffer_info = {0};
|
struct scm_buffer_info_t video_frame_buffer_info = {0};
|
||||||
static struct multiboot_tag_framebuffer_info_t __fb_info;
|
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 struct process_control_block *video_daemon_pcb = NULL;
|
||||||
static spinlock_t daemon_refresh_lock;
|
static spinlock_t daemon_refresh_lock;
|
||||||
|
|
||||||
@ -35,9 +35,9 @@ void init_frame_buffer()
|
|||||||
kinfo("Re-mapping VBE frame buffer...");
|
kinfo("Re-mapping VBE frame buffer...");
|
||||||
|
|
||||||
video_frame_buffer_info.vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET;
|
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);
|
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!");
|
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 (rs_clock() >= video_refresh_expire_jiffies)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (likely(video_refresh_target != NULL))
|
if (likely(video_refresh_target.size != 0))
|
||||||
{
|
{
|
||||||
spin_lock(&daemon_refresh_lock);
|
spin_lock(&daemon_refresh_lock);
|
||||||
if (video_frame_buffer_info.vaddr != NULL)
|
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);
|
spin_unlock(&daemon_refresh_lock);
|
||||||
video_daemon_pcb->virtual_runtime =
|
video_daemon_pcb->virtual_runtime =
|
||||||
0xfffff0000000; // 临时解决由于显示刷新进程的虚拟运行时间过大/过小,导致其不运行,或者一直运行的问题。将来应使用实时调度解决它
|
0xfffff0000000; // 临时解决由于显示刷新进程的虚拟运行时间过大/过小,导致其不运行,或者一直运行的问题。将来应使用实时调度解决它
|
||||||
@ -76,6 +80,10 @@ int video_refresh_daemon(void *unused)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t get_video_refresh_target_vaddr()
|
||||||
|
{
|
||||||
|
return video_refresh_target.vaddr;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @brief 唤醒video的守护进程
|
* @brief 唤醒video的守护进程
|
||||||
*/
|
*/
|
||||||
@ -105,10 +113,13 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
|
|||||||
{
|
{
|
||||||
rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
|
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守护进程
|
||||||
video_daemon_pcb = kthread_run(&video_refresh_daemon, NULL, "Video refresh daemon");
|
video_daemon_pcb = kthread_run(&video_refresh_daemon, NULL, "Video refresh daemon");
|
||||||
|
io_mfence();
|
||||||
video_daemon_pcb->virtual_runtime = 0; // 特殊情况, 最高优先级, 以后再改
|
video_daemon_pcb->virtual_runtime = 0; // 特殊情况, 最高优先级, 以后再改
|
||||||
// 启用屏幕刷新软中断
|
// 启用屏幕刷新软中断
|
||||||
rs_register_softirq_video();
|
rs_register_softirq_video();
|
||||||
@ -123,7 +134,8 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
|
|||||||
* @param buf
|
* @param buf
|
||||||
* @return int
|
* @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);
|
rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
|
||||||
@ -137,10 +149,11 @@ int video_set_refresh_target(struct scm_buffer_info_t *buf)
|
|||||||
// rs_usleep(1000);
|
// rs_usleep(1000);
|
||||||
// }
|
// }
|
||||||
// kdebug("buf = %#018lx", buf);
|
// kdebug("buf = %#018lx", buf);
|
||||||
|
|
||||||
video_refresh_target = buf;
|
video_refresh_target = buf;
|
||||||
|
|
||||||
rs_register_softirq_video();
|
rs_register_softirq_video();
|
||||||
kdebug("register softirq video done");
|
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(&video_frame_buffer_info, 0, sizeof(struct scm_buffer_info_t));
|
||||||
memset(&__fb_info, 0, sizeof(struct multiboot_tag_framebuffer_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();
|
io_mfence();
|
||||||
// 从multiboot2获取帧缓冲区信息
|
// 从multiboot2获取帧缓冲区信息
|
||||||
int reserved;
|
int reserved;
|
||||||
@ -180,17 +193,21 @@ int video_init()
|
|||||||
|
|
||||||
video_frame_buffer_info.size =
|
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.width * video_frame_buffer_info.height * ((video_frame_buffer_info.bit_depth + 7) / 8);
|
||||||
// 先临时映射到该地址,稍后再重新映射
|
// 先临时映射到50M的位置,稍后再重新映射
|
||||||
video_frame_buffer_info.vaddr = 0xffff800003000000;
|
video_frame_buffer_info.vaddr = 0xffff800003200000;
|
||||||
|
|
||||||
char init_text1[] = "Video driver to map.\n";
|
char init_text1[] = "Video driver to map.\n";
|
||||||
for (int i = 0; i < sizeof(init_text1) - 1; ++i)
|
for (int i = 0; i < sizeof(init_text1) - 1; ++i)
|
||||||
c_uart_send(COM1, init_text1[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);
|
rs_pseudo_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size);
|
||||||
|
|
||||||
io_mfence();
|
io_mfence();
|
||||||
char init_text2[] = "Video driver initialized.\n";
|
char init_text2[] = "Video driver initialized.\n";
|
||||||
for (int i = 0; i < sizeof(init_text2) - 1; ++i)
|
for (int i = 0; i < sizeof(init_text2) - 1; ++i)
|
||||||
|
{
|
||||||
c_uart_send(COM1, init_text2[i]);
|
c_uart_send(COM1, init_text2[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <common/glib.h>
|
#include <common/glib.h>
|
||||||
#include <stdbool.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 重新初始化显示驱动,需先低级初始化才能高级初始化
|
* @brief 重新初始化显示驱动,需先低级初始化才能高级初始化
|
||||||
* @param level 初始化等级
|
* @param level 初始化等级
|
||||||
@ -25,9 +25,11 @@ int video_init();
|
|||||||
* @param buf
|
* @param buf
|
||||||
* @return int
|
* @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_refresh_expire_jiffies;
|
||||||
extern uint64_t video_last_refresh_pid;
|
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
|
loop .fill_pde_64
|
||||||
|
|
||||||
// 最低级
|
// 最低级
|
||||||
// 循环 512*50=25600 次,填满50页
|
// 循环 512*25=12800 次,填满25页,共50M
|
||||||
mov $25600, %ecx
|
mov $12800, %ecx
|
||||||
mov $__PT_S, %eax
|
mov $__PT_S, %eax
|
||||||
mov $0x3, %ebx
|
mov $0x3, %ebx
|
||||||
.fill_pt_64:
|
.fill_pt_64:
|
||||||
@ -297,6 +297,14 @@ ENTRY(_start64)
|
|||||||
add $8, %eax
|
add $8, %eax
|
||||||
loop .fill_pt_64
|
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寄存器
|
// ==== 加载CR3寄存器
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#include <exception/gate.h>
|
#include <exception/gate.h>
|
||||||
#include <include/DragonOS/refcount.h>
|
#include <include/DragonOS/refcount.h>
|
||||||
#include <include/DragonOS/signal.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-types.h>
|
||||||
#include <mm/mm.h>
|
#include <mm/mm.h>
|
||||||
#include <mm/mmio.h>
|
#include <mm/mmio.h>
|
||||||
|
@ -54,16 +54,16 @@ extern crate thingbuf;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
extern crate x86;
|
extern crate x86;
|
||||||
|
|
||||||
|
use crate::libs::lib_ui::textui::FontColor;
|
||||||
use crate::mm::allocator::kernel_allocator::KernelAllocator;
|
use crate::mm::allocator::kernel_allocator::KernelAllocator;
|
||||||
|
|
||||||
// <3>
|
// <3>
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::asm::current::current_pcb,
|
arch::asm::current::current_pcb, include::bindings::bindings::process_do_exit,
|
||||||
include::bindings::bindings::{process_do_exit, BLACK, GREEN},
|
|
||||||
net::net_core::net_init,
|
net::net_core::net_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 声明全局的slab分配器
|
// 声明全局的分配器
|
||||||
#[cfg_attr(not(test), global_allocator)]
|
#[cfg_attr(not(test), global_allocator)]
|
||||||
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
|
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ pub fn panic(info: &PanicInfo) -> ! {
|
|||||||
/// 该函数用作测试,在process.c的initial_kernel_thread()中调用了此函数
|
/// 该函数用作测试,在process.c的initial_kernel_thread()中调用了此函数
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn __rust_demo_func() -> i32 {
|
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();
|
let r = net_init();
|
||||||
if r.is_err() {
|
if r.is_err() {
|
||||||
kwarn!("net_init() failed: {:?}", r.err().unwrap());
|
kwarn!("net_init() failed: {:?}", r.err().unwrap());
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
CFLAGS += -I .
|
CFLAGS += -I .
|
||||||
|
|
||||||
kernel_lib_subdirs:= libUI sys
|
kernel_lib_subdirs:= sys
|
||||||
|
|
||||||
kernel_lib_objs:= $(shell find ./*.c)
|
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 int_like;
|
||||||
pub mod keyboard_parser;
|
pub mod keyboard_parser;
|
||||||
pub mod lazy_init;
|
pub mod lazy_init;
|
||||||
|
pub mod lib_ui;
|
||||||
pub mod list;
|
pub mod list;
|
||||||
pub mod lockref;
|
pub mod lockref;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
#include <common/printk.h>
|
#include <common/printk.h>
|
||||||
|
|
||||||
#include <common/spinlock.h>
|
#include <common/spinlock.h>
|
||||||
#include <libs/libUI/textui.h>
|
#include <libs/lib_ui/textui.h>
|
||||||
#include <mm/mm.h>
|
#include <mm/mm.h>
|
||||||
|
|
||||||
#include <common/math.h>
|
#include <common/math.h>
|
||||||
@ -610,7 +610,7 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
|
|||||||
{
|
{
|
||||||
current = *(buf + i);
|
current = *(buf + i);
|
||||||
// 输出
|
// 输出
|
||||||
textui_putchar(current, FRcolor, BKcolor);
|
rs_textui_putchar(current, FRcolor, BKcolor);
|
||||||
}
|
}
|
||||||
io_mfence();
|
io_mfence();
|
||||||
spin_unlock_irqrestore(&__printk_lock, rflags);
|
spin_unlock_irqrestore(&__printk_lock, rflags);
|
||||||
|
@ -1,35 +1,6 @@
|
|||||||
#![allow(unused)]
|
use core::fmt::{self, Write};
|
||||||
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 super::lib_ui::textui::{textui_putchar, FontColor};
|
||||||
/// 白色
|
|
||||||
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;
|
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
@ -74,7 +45,7 @@ macro_rules! kinfo {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! kwarn {
|
macro_rules! kwarn {
|
||||||
($($arg:tt)*) => {
|
($($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)*)));
|
$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_export]
|
||||||
macro_rules! kerror {
|
macro_rules! kerror {
|
||||||
($($arg:tt)*) => {
|
($($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)*)));
|
$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_export]
|
||||||
macro_rules! kBUG {
|
macro_rules! kBUG {
|
||||||
($($arg:tt)*) => {
|
($($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)*)));
|
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PrintkWriter;
|
pub struct PrintkWriter;
|
||||||
|
|
||||||
/// 由于内存管理初始化完成之前,无法使用动态内存分配,所以需要在内存管理初始化完成之后才能使用动态内存分配
|
|
||||||
static ALLOW_ALLOC_ATOMIC: AtomicBool = AtomicBool::new(false);
|
|
||||||
static mut ALLOW_ALLOC_BOOL: bool = false;
|
|
||||||
|
|
||||||
impl PrintkWriter {
|
impl PrintkWriter {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn __write_fmt(&mut self, args: fmt::Arguments) {
|
pub fn __write_fmt(&mut self, args: fmt::Arguments) {
|
||||||
self.write_fmt(args);
|
self.write_fmt(args).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 调用C语言编写的printk_color,并输出白底黑字(暂时只支持ascii字符)
|
/// 并输出白底黑字
|
||||||
/// @param str: 要写入的字符
|
/// @param str: 要写入的字符
|
||||||
pub fn __write_string(&mut self, s: &str) {
|
pub fn __write_string(&mut self, s: &str) {
|
||||||
if unlikely(!self.allow_alloc()) {
|
for c in s.chars() {
|
||||||
self.__write_string_on_stack(s);
|
textui_putchar(c, FontColor::WHITE, FontColor::BLACK).ok();
|
||||||
return;
|
|
||||||
}
|
|
||||||
let str_to_print = self.__utf8_to_ascii(s);
|
|
||||||
unsafe {
|
|
||||||
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
|
pub fn __write_string_color(&self, fr_color: FontColor, bk_color: FontColor, s: &str) {
|
||||||
if unlikely(!self.allow_alloc()) {
|
for c in s.chars() {
|
||||||
self.__write_string_on_stack(s);
|
textui_putchar(c, fr_color, bk_color).ok();
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,6 +99,5 @@ impl fmt::Write for PrintkWriter {
|
|||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn __printk(args: fmt::Arguments) {
|
pub fn __printk(args: fmt::Arguments) {
|
||||||
use fmt::Write;
|
|
||||||
PrintkWriter.write_fmt(args).unwrap();
|
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::asm::irqflags::{local_irq_restore, local_irq_save};
|
||||||
use crate::arch::interrupt::{cli, sti};
|
use crate::arch::interrupt::{cli, sti};
|
||||||
|
|
||||||
use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
|
use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
|
||||||
use crate::process::preempt::{preempt_disable, preempt_enable};
|
use crate::process::preempt::{preempt_disable, preempt_enable};
|
||||||
use crate::syscall::SystemError;
|
use crate::syscall::SystemError;
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
#include "smp/smp.h"
|
#include "smp/smp.h"
|
||||||
#include "syscall/syscall.h"
|
#include "syscall/syscall.h"
|
||||||
#include <exception/softirq.h>
|
#include <exception/softirq.h>
|
||||||
#include <libs/libUI/screen_manager.h>
|
#include <libs/lib_ui/screen_manager.h>
|
||||||
#include <libs/libUI/textui.h>
|
#include <libs/lib_ui/textui.h>
|
||||||
#include <sched/sched.h>
|
#include <sched/sched.h>
|
||||||
#include <smp/ipi.h>
|
#include <smp/ipi.h>
|
||||||
|
|
||||||
@ -71,10 +71,10 @@ void reload_idt()
|
|||||||
void system_initialize()
|
void system_initialize()
|
||||||
{
|
{
|
||||||
c_uart_init(COM1, 115200);
|
c_uart_init(COM1, 115200);
|
||||||
|
|
||||||
video_init();
|
video_init();
|
||||||
|
|
||||||
scm_init();
|
scm_init();
|
||||||
textui_init();
|
|
||||||
kinfo("Kernel Starting...");
|
|
||||||
// 重新加载gdt和idt
|
// 重新加载gdt和idt
|
||||||
ul tss_item_addr = (ul)phys_2_virt(0x7c00);
|
ul tss_item_addr = (ul)phys_2_virt(0x7c00);
|
||||||
|
|
||||||
@ -92,7 +92,6 @@ void system_initialize()
|
|||||||
|
|
||||||
// 初始化中断描述符表
|
// 初始化中断描述符表
|
||||||
sys_vector_init();
|
sys_vector_init();
|
||||||
|
|
||||||
// 初始化内存管理单元
|
// 初始化内存管理单元
|
||||||
// mm_init();
|
// mm_init();
|
||||||
rs_mm_init();
|
rs_mm_init();
|
||||||
@ -101,8 +100,12 @@ void system_initialize()
|
|||||||
// 原因是,系统启动初期,framebuffer被映射到48M地址处,
|
// 原因是,系统启动初期,framebuffer被映射到48M地址处,
|
||||||
// mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃
|
// mm初始化完毕后,若不重新初始化显示驱动,将会导致错误的数据写入内存,从而造成其他模块崩溃
|
||||||
// 对显示模块进行低级初始化,不启用double buffer
|
// 对显示模块进行低级初始化,不启用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
|
// =========== 重新设置initial_tss[0]的ist
|
||||||
uchar *ptr = (uchar *)kzalloc(STACK_SIZE, 0) + STACK_SIZE;
|
uchar *ptr = (uchar *)kzalloc(STACK_SIZE, 0) + STACK_SIZE;
|
||||||
((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0;
|
((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
|
target remote localhost:1234
|
||||||
file bin/kernel/kernel.elf
|
file bin/kernel/kernel.elf
|
||||||
set follow-fork-mode child
|
set follow-fork-mode child
|
||||||
b Start_Kernel
|
|
@ -506,6 +506,7 @@ int shell_cmd_exec(int argc, char **argv)
|
|||||||
int path_len = 0;
|
int path_len = 0;
|
||||||
char *file_path = get_target_filepath(argv[1], &path_len);
|
char *file_path = get_target_filepath(argv[1], &path_len);
|
||||||
// printf("before execv, path=%s, argc=%d\n", file_path, argc);
|
// printf("before execv, path=%s, argc=%d\n", file_path, argc);
|
||||||
|
|
||||||
execv(file_path, argv);
|
execv(file_path, argv);
|
||||||
// printf("after execv, path=%s, argc=%d\n", file_path, argc);
|
// printf("after execv, path=%s, argc=%d\n", file_path, argc);
|
||||||
free(argv);
|
free(argv);
|
||||||
@ -527,6 +528,7 @@ int shell_cmd_exec(int argc, char **argv)
|
|||||||
|
|
||||||
int shell_cmd_about(int argc, char **argv)
|
int shell_cmd_about(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (argv != NULL)
|
if (argv != NULL)
|
||||||
free(argv);
|
free(argv);
|
||||||
int aac = 0;
|
int aac = 0;
|
||||||
|
@ -79,8 +79,12 @@ void main_loop(int kb_fd)
|
|||||||
strcpy(command_origin, input_buffer);
|
strcpy(command_origin, input_buffer);
|
||||||
int cmd_num = parse_command(input_buffer, &argc, &argv);
|
int cmd_num = parse_command(input_buffer, &argc, &argv);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
|
|
||||||
if (cmd_num >= 0)
|
if (cmd_num >= 0)
|
||||||
shell_run_built_in_command(cmd_num, argc, argv);
|
shell_run_built_in_command(cmd_num, argc, argv);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -155,6 +155,7 @@ int execv(const char *path, char *const argv[])
|
|||||||
errno = -ENOENT;
|
errno = -ENOENT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
|
int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user