Patch refactor scm and textui (#289)

* 重构屏幕管理器和textui框架

* 切换字体为spleen,并增加对字体的抽象

* 修正文档

---------

Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
hanjiezhou 2023-08-20 00:19:36 +08:00 committed by GitHub
parent 5db5a5652c
commit abe3a6ea3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 2005 additions and 1726 deletions

View File

@ -4,7 +4,6 @@
"stdbool.h": "c",
"printk.h": "c",
"stdarg.h": "c",
"font.h": "c",
"trap.h": "c",
"gate.h": "c",
"process.h": "c",

View File

@ -29,6 +29,7 @@
kernel/debug/index
kernel/ktest/index
kernel/cpu_arch/index
kernel/libs/index
.. toctree::

View File

@ -0,0 +1,12 @@
====================================
其他内核库
====================================
这里的集中了内核中的一些库的文档,这些库不属于任何子系统。
.. toctree::
:maxdepth: 1
lib_ui/scm
lib_ui/textui

View File

@ -0,0 +1,83 @@
# 屏幕管理器SCM
:::{note}
作者: 周瀚杰 <2625553453@qq.com>
:::
&emsp;&emsp;屏幕管理器用来管理控制所有ui框架所有框架都必须先在屏幕管理器中注册才可使用然后scm控制当前是哪个ui框架在使用
## traits
### ScmUiFramework
&emsp;&emsp;每个要注册到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()
```
#### 说明
&emsp;&emsp;scm_init()主要是初始化一些scm中使用的全局变量例如是否使用双缓冲区标志位textui未初始化时使用的一些全局变量
### scm_reinit() -当内存管理单元被初始化之后,重新初始化屏幕管理模块
#### 原型
```rust
pub extern "C" fn scm_reinit() -> i32
```
#### 说明
&emsp;&emsp;scm_reinit()用于当内存管理单元被初始化之后,重新处理帧缓冲区问题
### scm_enable_double_buffer() -允许双缓冲区
#### 原型
```rust
pub extern "C" fn scm_enable_double_buffer() -> i32
```
#### 说明
&emsp;&emsp;scm_enable_double_buffer()用于启动双缓冲来往窗口输出打印信息。启用后,往窗口输出的信息会暂时放在一个缓冲区中,然后每次按一定时间将该缓冲区的信息输出到窗口帧缓冲区中,渲染显示到窗口上。
### scm_framework_enable -启用某个ui框架将它的帧缓冲区渲染到屏幕上
#### 原型
```rust
pub fn scm_framework_enable(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError>
```
#### 说明
&emsp;&emsp;scm_framework_enable用于启用某个ui框架将它的帧缓冲区渲染到屏幕上
### scm_register -向屏幕管理器注册UI框架
#### 原型
```rust
pub fn scm_register(framework: Arc<dyn ScmUiFramework>) -> Result<i32, SystemError>
```
#### 说明
&emsp;&emsp;scm_register用于将ui框架注册到scm中主要是调用ui框架的回调函数以安装ui框架并将其激活

View File

@ -0,0 +1,32 @@
# 文本显示框架textui
:::{note}
作者: 周瀚杰 <2625553453@qq.com>
:::
&emsp;&emsp;文本框架主要用于DragonOS的文本的窗口渲染显示往屏幕窗口中输出打印文本信息往窗口显示文本分成两种情况一种是当内存管理单元mm未被初始化时不能进行动态内存分配限制颇多例如不能使用vec,mpsc等所以直接往窗口的帧缓冲区输出打印信息不使用虚拟行等复杂结构体另一种是当内存管理单元mm已经初始化可以进行动态内存分配便可以使用一些复杂的结构体来处理要打印的文本信息。
## 主要API
### rs_textui_init() -textui框架初始化
#### 原型
```rust
pub extern "C" fn rs_textui_init() -> i32
```
#### 说明
&emsp;&emsp;rs_textui_init()主要是初始化一些textui框架要使用到的一些全局变量信息例如TEXTUIFRAMEWORKTEXTUI_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>
```
#### 说明
&emsp;&emsp;textui_putchar()要处理两种情况一种是当内存管理单元mm未被初始化时不能进行动态内存分配限制颇多例如不能使用vec,mpsc等所以直接往窗口的帧缓冲区输出打印信息不使用虚拟行等复杂结构体另一种是当内存管理单元mm已经初始化可以进行动态内存分配便可以使用一些复杂的结构体来处理要打印的文本信息。

View File

@ -7,10 +7,10 @@ use x86_64::registers::model_specific::EferFlags;
use crate::driver::uart::uart::c_uart_send_str;
use crate::include::bindings::bindings::{
disable_textui, enable_textui, multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
video_reinitialize,
multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
};
use crate::libs::align::page_align_up;
use crate::libs::lib_ui::screen_manager::scm_disable_put_to_window;
use crate::libs::printk::PrintkWriter;
use crate::libs::spinlock::SpinLock;
@ -315,8 +315,6 @@ pub fn mm_init() {
unsafe { allocator_init() };
// enable mmio
mmio_init();
// 启用printk的alloc选项
PrintkWriter.enable_alloc();
}
unsafe fn allocator_init() {
@ -396,9 +394,8 @@ unsafe fn allocator_init() {
unsafe { set_inner_allocator(buddy_allocator) };
kinfo!("Successfully initialized buddy allocator");
// 关闭显示输出
unsafe {
disable_textui();
}
scm_disable_put_to_window();
// make the new page table current
{
let mut binding = INNER_ALLOCATOR.lock();
@ -416,16 +413,6 @@ unsafe fn allocator_init() {
kdebug!("New page table enabled");
}
kdebug!("Successfully enabled new page table");
// 重置显示输出目标
unsafe {
video_reinitialize(false);
}
// 打开显示输出
unsafe {
enable_textui();
}
kdebug!("Text UI enabled");
}
#[no_mangle]

View File

@ -11,8 +11,8 @@
#pragma once
#include <arch/x86_64/include/asm/cmpxchg.h>
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
#define atomic_set(atomic,val) (((atomic)->value) = (val)) // 设置原子变量的初始值
#define atomic_read(atomic) ((atomic)->value) // 读取原子变量
#define atomic_set(atomic, val) (((atomic)->value) = (val)) // 设置原子变量的初始值
typedef struct
{

View File

@ -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},
};

View File

@ -16,29 +16,25 @@
#define is_digit(c) ((c) >= '0' && (c) <= '9') // 用来判断是否是数字的宏
// 字体颜色的宏定义
#define WHITE 0x00ffffff //
#define BLACK 0x00000000 //
#define RED 0x00ff0000 //
#define ORANGE 0x00ff8000 //
#define YELLOW 0x00ffff00 //
#define GREEN 0x0000ff00 //绿
#define BLUE 0x000000ff //
#define INDIGO 0x0000ffff //
#define PURPLE 0x008000ff //
#define WHITE 0x00ffffff //
#define BLACK 0x00000000 //
#define RED 0x00ff0000 //
#define ORANGE 0x00ff8000 //
#define YELLOW 0x00ffff00 //
#define GREEN 0x0000ff00 // 绿
#define BLUE 0x000000ff //
#define INDIGO 0x0000ffff //
#define PURPLE 0x008000ff //
// 异常的宏定义
#define EPOS_OVERFLOW 1 // 坐标溢出
#define EFB_MISMATCH 2 // 帧缓冲区与指定的屏幕大小不匹配
#define EUNSUPPORTED 3 // 当前操作暂不被支持
#include "font.h"
#include "glib.h"
#include <libs/libUI/screen_manager.h>
#include <libs/lib_ui/screen_manager.h>
#include <stdarg.h>
extern unsigned char font_ascii[256][16]; //导出ascii字体的bitmap8*16大小 ps:位于font.h中
/**
* @brief fmt和args中的内容进行格式化buf中
*

View File

@ -326,7 +326,7 @@ void apic_local_apic_init()
// 检测是否成功启用xAPIC和x2APIC
if ((eax & 0xc00) == 0xc00)
kinfo("xAPIC & x2APIC enabled!");
kinfo("xAPIC & x2APIC enabled!\n");
else if ((eax & 0x800) == 0x800)
kinfo("Only xAPIC enabled!");
else

View File

@ -9,9 +9,11 @@ use crate::{
devfs::{devfs_register, DevFS, DeviceINode},
vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
},
include::bindings::bindings::{textui_putchar, BLACK, WHITE},
kerror,
libs::rwlock::RwLock,
libs::{
lib_ui::textui::{textui_putchar, FontColor},
rwlock::RwLock,
},
syscall::SystemError,
};
@ -255,10 +257,9 @@ impl IndexNode for TtyDevice {
break;
}
// 输出到屏幕
unsafe {
for x in buf {
textui_putchar(x as u16, WHITE, BLACK);
}
for x in buf {
textui_putchar(x as char, FontColor::WHITE, FontColor::BLACK).ok();
}
}
return Ok(());

View File

@ -17,10 +17,10 @@ extern void rs_register_softirq_video();
uint64_t video_refresh_expire_jiffies = 0;
uint64_t video_last_refresh_pid = -1;
struct scm_buffer_info_t video_frame_buffer_info = {0};
static struct multiboot_tag_framebuffer_info_t __fb_info;
static struct scm_buffer_info_t *video_refresh_target = NULL;
// static struct scm_buffer_info_t *_video_refresh_target = NULL;
static struct scm_buffer_info_t video_refresh_target = {0};
static struct process_control_block *video_daemon_pcb = NULL;
static spinlock_t daemon_refresh_lock;
@ -35,9 +35,9 @@ void init_frame_buffer()
kinfo("Re-mapping VBE frame buffer...");
video_frame_buffer_info.vaddr = SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + FRAME_BUFFER_MAPPING_OFFSET;
rs_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size, PAGE_KERNEL_PAGE | PAGE_PWT | PAGE_PCD);
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
kinfo("VBE frame buffer successfully Re-mapped!");
}
@ -56,12 +56,16 @@ int video_refresh_daemon(void *unused)
if (rs_clock() >= video_refresh_expire_jiffies)
{
if (likely(video_refresh_target != NULL))
if (likely(video_refresh_target.size != 0))
{
spin_lock(&daemon_refresh_lock);
if (video_frame_buffer_info.vaddr != NULL)
memcpy((void *)video_frame_buffer_info.vaddr, (void *)video_refresh_target->vaddr,
video_refresh_target->size);
{
// kdebug("video_frame_buffer_info.vaddr = %#018lx,get_video_refresh_target_vaddr()= %#018lx" ,video_frame_buffer_info.vaddr,get_video_refresh_target_vaddr());
memcpy((void *)video_frame_buffer_info.vaddr, (void *)get_video_refresh_target_vaddr(),
video_refresh_target.size);
}
spin_unlock(&daemon_refresh_lock);
video_daemon_pcb->virtual_runtime =
0xfffff0000000; // 临时解决由于显示刷新进程的虚拟运行时间过大/过小,导致其不运行,或者一直运行的问题。将来应使用实时调度解决它
@ -76,6 +80,10 @@ int video_refresh_daemon(void *unused)
return 0;
}
uint64_t get_video_refresh_target_vaddr()
{
return video_refresh_target.vaddr;
}
/**
* @brief video的守护进程
*/
@ -105,10 +113,13 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
{
rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
// 计算开始时间
video_refresh_expire_jiffies = rs_timer_next_n_ms_jiffies(10 * REFRESH_INTERVAL);
video_refresh_expire_jiffies = rs_timer_next_n_ms_jiffies(50 * REFRESH_INTERVAL);
kdebug("video_frame_buffer_info.vaddr = %#018lx,get_video_refresh_target_vaddr()= %#018lx", video_frame_buffer_info.vaddr, get_video_refresh_target_vaddr());
io_mfence();
// 创建video守护进程
video_daemon_pcb = kthread_run(&video_refresh_daemon, NULL, "Video refresh daemon");
io_mfence();
video_daemon_pcb->virtual_runtime = 0; // 特殊情况, 最高优先级, 以后再改
// 启用屏幕刷新软中断
rs_register_softirq_video();
@ -123,7 +134,8 @@ int video_reinitialize(bool level) // 这个函数会在main.c调用, 保证 vid
* @param buf
* @return int
*/
int video_set_refresh_target(struct scm_buffer_info_t *buf)
int video_set_refresh_target(struct scm_buffer_info_t buf)
{
rs_unregister_softirq(VIDEO_REFRESH_SIRQ);
@ -137,10 +149,11 @@ int video_set_refresh_target(struct scm_buffer_info_t *buf)
// rs_usleep(1000);
// }
// kdebug("buf = %#018lx", buf);
video_refresh_target = buf;
rs_register_softirq_video();
kdebug("register softirq video done");
// rs_raise_softirq(VIDEO_REFRESH_SIRQ);
}
/**
@ -153,8 +166,8 @@ int video_init()
memset(&video_frame_buffer_info, 0, sizeof(struct scm_buffer_info_t));
memset(&__fb_info, 0, sizeof(struct multiboot_tag_framebuffer_info_t));
video_refresh_target = NULL;
// _video_refresh_target = NULL;
video_refresh_target = (struct scm_buffer_info_t){0};
io_mfence();
// 从multiboot2获取帧缓冲区信息
int reserved;
@ -180,17 +193,21 @@ int video_init()
video_frame_buffer_info.size =
video_frame_buffer_info.width * video_frame_buffer_info.height * ((video_frame_buffer_info.bit_depth + 7) / 8);
// 先临时映射到该地址,稍后再重新映射
video_frame_buffer_info.vaddr = 0xffff800003000000;
// 先临时映射到50M的位置稍后再重新映射
video_frame_buffer_info.vaddr = 0xffff800003200000;
char init_text1[] = "Video driver to map.\n";
for (int i = 0; i < sizeof(init_text1) - 1; ++i)
c_uart_send(COM1, init_text1[i]);
rs_pseudo_map_phys(video_frame_buffer_info.vaddr, __fb_info.framebuffer_addr, video_frame_buffer_info.size);
io_mfence();
char init_text2[] = "Video driver initialized.\n";
for (int i = 0; i < sizeof(init_text2) - 1; ++i)
{
c_uart_send(COM1, init_text2[i]);
}
return 0;
}

View File

@ -1,8 +1,8 @@
#pragma once
#include <common/glib.h>
#include <stdbool.h>
#include <libs/libUI/screen_manager.h>
#include <libs/lib_ui/screen_manager.h>
extern struct scm_buffer_info_t video_frame_buffer_info;
/**
* @brief
* @param level
@ -21,13 +21,15 @@ int video_init();
/**
* @brief
*
* @param buf
* @return int
*
* @param buf
* @return int
*/
int video_set_refresh_target(struct scm_buffer_info_t *buf);
// int video_set_refresh_target(struct scm_buffer_info_t *buf);
int video_set_refresh_target(struct scm_buffer_info_t buf);
extern uint64_t video_refresh_expire_jiffies;
extern uint64_t video_last_refresh_pid;
void video_refresh_framebuffer(void *data);
void video_refresh_framebuffer(void *data);
uint64_t get_video_refresh_target_vaddr();

View File

@ -287,8 +287,8 @@ ENTRY(_start64)
loop .fill_pde_64
//
// 512*50=25600 50
mov $25600, %ecx
// 512*25=12800 2550M
mov $12800, %ecx
mov $__PT_S, %eax
mov $0x3, %ebx
.fill_pt_64:
@ -297,6 +297,14 @@ ENTRY(_start64)
add $8, %eax
loop .fill_pt_64
// 50-100M025
mov $12800, %ecx
.fill_pt_64_2:
mov $0, 0(%eax)
add $8, %eax
loop .fill_pt_64_2
// ==== CR3

View File

@ -38,7 +38,7 @@
#include <exception/gate.h>
#include <include/DragonOS/refcount.h>
#include <include/DragonOS/signal.h>
#include <libs/libUI/textui.h>
#include <libs/lib_ui/textui.h>
#include <mm/mm-types.h>
#include <mm/mm.h>
#include <mm/mmio.h>

View File

@ -54,16 +54,16 @@ extern crate thingbuf;
#[cfg(target_arch = "x86_64")]
extern crate x86;
use crate::libs::lib_ui::textui::FontColor;
use crate::mm::allocator::kernel_allocator::KernelAllocator;
// <3>
use crate::{
arch::asm::current::current_pcb,
include::bindings::bindings::{process_do_exit, BLACK, GREEN},
arch::asm::current::current_pcb, include::bindings::bindings::process_do_exit,
net::net_core::net_init,
};
// 声明全局的slab分配器
// 声明全局的分配器
#[cfg_attr(not(test), global_allocator)]
pub static KERNEL_ALLOCATOR: KernelAllocator = KernelAllocator;
@ -106,7 +106,7 @@ pub fn panic(info: &PanicInfo) -> ! {
/// 该函数用作测试在process.c的initial_kernel_thread()中调用了此函数
#[no_mangle]
pub extern "C" fn __rust_demo_func() -> i32 {
printk_color!(GREEN, BLACK, "__rust_demo_func()\n");
printk_color!(FontColor::GREEN, FontColor::BLACK, "__rust_demo_func()\n");
let r = net_init();
if r.is_err() {
kwarn!("net_init() failed: {:?}", r.err().unwrap());

View File

@ -1,7 +1,7 @@
CFLAGS += -I .
kernel_lib_subdirs:= libUI sys
kernel_lib_subdirs:= sys
kernel_lib_objs:= $(shell find ./*.c)

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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字体的bitmap8*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;
}
}

View File

@ -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);
}

View File

@ -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();

View 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()
}
}

View 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),
);

View File

@ -0,0 +1,4 @@
pub mod font;
pub mod screen_manager;
pub mod textui;
pub mod textui_no_alloc;

View 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();

View 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);
}

View 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();

View 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_operatingwindow.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);
}

View 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(());
}

View File

@ -7,6 +7,7 @@ pub mod ffi_convert;
pub mod int_like;
pub mod keyboard_parser;
pub mod lazy_init;
pub mod lib_ui;
pub mod list;
pub mod lockref;
pub mod mutex;

View File

@ -5,7 +5,7 @@
#include <common/printk.h>
#include <common/spinlock.h>
#include <libs/libUI/textui.h>
#include <libs/lib_ui/textui.h>
#include <mm/mm.h>
#include <common/math.h>
@ -610,7 +610,7 @@ int printk_color(unsigned int FRcolor, unsigned int BKcolor, const char *fmt, ..
{
current = *(buf + i);
// 输出
textui_putchar(current, FRcolor, BKcolor);
rs_textui_putchar(current, FRcolor, BKcolor);
}
io_mfence();
spin_unlock_irqrestore(&__printk_lock, rflags);

View File

@ -1,35 +1,6 @@
#![allow(unused)]
use crate::{
driver::uart::uart::c_uart_send_str,
include::bindings::bindings::{printk_color, BLACK, WHITE},
};
use ::core::ffi::c_char;
use alloc::vec::Vec;
use core::{
fmt::{self, Write},
intrinsics::{likely, unlikely},
sync::atomic::{AtomicBool, Ordering},
};
use core::fmt::{self, Write};
// ====== 定义颜色 ======
/// 白色
pub const COLOR_WHITE: u32 = 0x00ffffff;
/// 黑色
pub const COLOR_BLACK: u32 = 0x00000000;
/// 红色
pub const COLOR_RED: u32 = 0x00ff0000;
/// 橙色
pub const COLOR_ORANGE: u32 = 0x00ff8000;
/// 黄色
pub const COLOR_YELLOW: u32 = 0x00ffff00;
/// 绿色
pub const COLOR_GREEN: u32 = 0x0000ff00;
/// 蓝色
pub const COLOR_BLUE: u32 = 0x000000ff;
/// 靛色
pub const COLOR_INDIGO: u32 = 0x0000ffff;
/// 紫色
pub const COLOR_PURPLE: u32 = 0x008000ff;
use super::lib_ui::textui::{textui_putchar, FontColor};
#[macro_export]
macro_rules! print {
@ -74,7 +45,7 @@ macro_rules! kinfo {
#[macro_export]
macro_rules! kwarn {
($($arg:tt)*) => {
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_YELLOW, $crate::libs::printk::COLOR_BLACK, "[ WARN ] ");
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::YELLOW, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ WARN ] ");
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
}
}
@ -82,7 +53,7 @@ macro_rules! kwarn {
#[macro_export]
macro_rules! kerror {
($($arg:tt)*) => {
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ ERROR ] ");
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ ERROR ] ");
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
}
}
@ -90,121 +61,30 @@ macro_rules! kerror {
#[macro_export]
macro_rules! kBUG {
($($arg:tt)*) => {
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::printk::COLOR_RED, $crate::libs::printk::COLOR_BLACK, "[ BUG ] ");
$crate::libs::printk::PrintkWriter.__write_string_color($crate::libs::lib_ui::textui::FontColor::RED, $crate::libs::lib_ui::textui::FontColor::BLACK, "[ BUG ] ");
$crate::libs::printk::PrintkWriter.__write_fmt(format_args!("({}:{})\t{}\n", file!(), line!(),format_args!($($arg)*)));
}
}
pub struct PrintkWriter;
/// 由于内存管理初始化完成之前,无法使用动态内存分配,所以需要在内存管理初始化完成之后才能使用动态内存分配
static ALLOW_ALLOC_ATOMIC: AtomicBool = AtomicBool::new(false);
static mut ALLOW_ALLOC_BOOL: bool = false;
impl PrintkWriter {
#[inline]
pub fn __write_fmt(&mut self, args: fmt::Arguments) {
self.write_fmt(args);
self.write_fmt(args).ok();
}
/// 调用C语言编写的printk_color,并输出白底黑字暂时只支持ascii字符
/// 并输出白底黑字
/// @param str: 要写入的字符
pub fn __write_string(&mut self, s: &str) {
if unlikely(!self.allow_alloc()) {
self.__write_string_on_stack(s);
return;
}
let str_to_print = self.__utf8_to_ascii(s);
unsafe {
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
for c in s.chars() {
textui_putchar(c, FontColor::WHITE, FontColor::BLACK).ok();
}
}
pub fn __write_string_color(&self, fr_color: u32, bk_color: u32, s: &str) {
if unlikely(!self.allow_alloc()) {
self.__write_string_on_stack(s);
return;
}
let str_to_print = self.__utf8_to_ascii(s);
unsafe {
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
}
}
#[inline]
fn allow_alloc(&self) -> bool {
// 由于allow_alloc只可能由false变为true
// 因此采用两种方式读取它一种是原子操作一种是普通的bool以优化性能。
if likely(unsafe { ALLOW_ALLOC_BOOL }) {
return true;
} else {
return ALLOW_ALLOC_ATOMIC.load(Ordering::SeqCst);
}
}
/// 允许动态内存分配
pub fn enable_alloc(&self) {
ALLOW_ALLOC_ATOMIC.store(true, Ordering::SeqCst);
unsafe {
ALLOW_ALLOC_BOOL = true;
}
}
/// 将s这个utf8字符串转换为ascii字符串
/// @param s 待转换的utf8字符串
/// @return Vec<u8> 转换结束后的Ascii字符串
pub fn __utf8_to_ascii(&self, s: &str) -> Vec<u8> {
let mut ascii_str: Vec<u8> = Vec::with_capacity(s.len() + 1);
for byte in s.bytes() {
match byte {
0..=127 => {
ascii_str.push(byte);
}
_ => {}
}
}
ascii_str.push(b'\0');
return ascii_str;
}
fn __write_string_on_stack(&self, s: &str) {
let s_len = s.len();
assert!(s_len < 1024, "s_len is too long");
let mut str_to_print: [u8; 1024] = [0; 1024];
let mut i = 0;
for byte in s.bytes() {
match byte {
0..=127 => {
str_to_print[i] = byte;
i += 1;
}
_ => {}
}
}
str_to_print[i] = b'\0';
unsafe {
printk_color(WHITE, BLACK, str_to_print.as_ptr() as *const c_char);
}
}
fn __write_string_color_on_stack(&self, fr_color: u32, bk_color: u32, s: &str) {
let s_len = s.len();
assert!(s_len < 1024, "s_len is too long");
let mut str_to_print: [u8; 1024] = [0; 1024];
let mut i = 0;
for byte in s.bytes() {
match byte {
0..=127 => {
str_to_print[i] = byte;
i += 1;
}
_ => {}
}
}
str_to_print[i] = b'\0';
unsafe {
printk_color(fr_color, bk_color, str_to_print.as_ptr() as *const c_char);
pub fn __write_string_color(&self, fr_color: FontColor, bk_color: FontColor, s: &str) {
for c in s.chars() {
textui_putchar(c, fr_color, bk_color).ok();
}
}
}
@ -219,6 +99,5 @@ impl fmt::Write for PrintkWriter {
#[doc(hidden)]
pub fn __printk(args: fmt::Arguments) {
use fmt::Write;
PrintkWriter.write_fmt(args).unwrap();
}

View File

@ -8,6 +8,7 @@ use core::sync::atomic::{AtomicBool, Ordering};
use crate::arch::asm::irqflags::{local_irq_restore, local_irq_save};
use crate::arch::interrupt::{cli, sti};
use crate::include::bindings::bindings::{spin_lock, spin_unlock, spinlock_t};
use crate::process::preempt::{preempt_disable, preempt_enable};
use crate::syscall::SystemError;

View File

@ -14,8 +14,8 @@
#include "smp/smp.h"
#include "syscall/syscall.h"
#include <exception/softirq.h>
#include <libs/libUI/screen_manager.h>
#include <libs/libUI/textui.h>
#include <libs/lib_ui/screen_manager.h>
#include <libs/lib_ui/textui.h>
#include <sched/sched.h>
#include <smp/ipi.h>
@ -71,10 +71,10 @@ void reload_idt()
void system_initialize()
{
c_uart_init(COM1, 115200);
video_init();
scm_init();
textui_init();
kinfo("Kernel Starting...");
// 重新加载gdt和idt
ul tss_item_addr = (ul)phys_2_virt(0x7c00);
@ -92,7 +92,6 @@ void system_initialize()
// 初始化中断描述符表
sys_vector_init();
// 初始化内存管理单元
// mm_init();
rs_mm_init();
@ -101,8 +100,12 @@ void system_initialize()
// 原因是系统启动初期framebuffer被映射到48M地址处
// mm初始化完毕后若不重新初始化显示驱动将会导致错误的数据写入内存从而造成其他模块崩溃
// 对显示模块进行低级初始化不启用double buffer
scm_reinit();
io_mfence();
scm_reinit();
rs_textui_init();
// kinfo("vaddr:%#018lx", video_frame_buffer_info.vaddr);
io_mfence();
// =========== 重新设置initial_tss[0]的ist
uchar *ptr = (uchar *)kzalloc(STACK_SIZE, 0) + STACK_SIZE;
((struct process_control_block *)(ptr - STACK_SIZE))->cpu_id = 0;

View File

@ -1,6 +1,7 @@
//! 该文件用于系统启动早期,内存管理器初始化之前,提供一些简单的内存映射功能
//!
//! 这里假设在内核引导文件中已经填写了前100M的内存映射关系因此这里不需要任何动态分配。
//! 这里假设在内核引导文件中已经填写了前100M的页表其中前50M是真实映射到内存的后面的仅仅创建了页表表项全部为0。
//! 因此这里映射内存不需要任何动态分配。
//!
//! 映射关系为:
//!

View File

@ -1,4 +1,3 @@
target remote localhost:1234
file bin/kernel/kernel.elf
set follow-fork-mode child
b Start_Kernel

View File

@ -506,6 +506,7 @@ int shell_cmd_exec(int argc, char **argv)
int path_len = 0;
char *file_path = get_target_filepath(argv[1], &path_len);
// printf("before execv, path=%s, argc=%d\n", file_path, argc);
execv(file_path, argv);
// printf("after execv, path=%s, argc=%d\n", file_path, argc);
free(argv);
@ -520,13 +521,14 @@ int shell_cmd_exec(int argc, char **argv)
waitpid(pid, &retval, 0);
else
printf("[1] %d\n", pid); // 输出子进程的pid
free(argv);
}
}
int shell_cmd_about(int argc, char **argv)
{
if (argv != NULL)
free(argv);
int aac = 0;

View File

@ -79,8 +79,12 @@ void main_loop(int kb_fd)
strcpy(command_origin, input_buffer);
int cmd_num = parse_command(input_buffer, &argc, &argv);
printf("\n");
if (cmd_num >= 0)
shell_run_built_in_command(cmd_num, argc, argv);
}
else
printf("\n");

View File

@ -155,6 +155,7 @@ int execv(const char *path, char *const argv[])
errno = -ENOENT;
return -1;
}
int retval = syscall_invoke(SYS_EXECVE, (uint64_t)path, (uint64_t)argv, 0, 0, 0, 0, 0, 0);
if (retval != 0)
return -1;