黑暗模式
6. 平台相关接口
6.1 文件系统移植
文件系统属于移植 AWTK 时的非必须功能,如果要使用文件模块的功能,比如想把 AWTK 应用的资源文件放到文件系统中管理,则需要对文件系统进行移植。在 AWTK 中,需要开启宏 WITH_FS_RES 来支持文件系统功能,更多关于通用文件模块描述请参考本文附录二。
移植文件系统需要实现 awtk/src/tkc/fs.h 中的相关接口,其中包括:文件操作接口(fs_file_t)、文件夹操作接口(fs_dir_t)以及文件系统操作接口(fs_t),因为接口太多就不在这里一一列举,具体详见本文附录一,完成以上适配工作后,只需实现获取文件系统对象的 os_fs 函数即可,示例代码详见下文。
1、实现 fs.h 中的相关接口
先实现文件读写操作接口 fs_file_vtable_t,以及文件夹遍历接口 fs_dir_vtable_t,代码片段如下:
c
static int32_t fs_os_file_read(fs_file_t* file, void* buffer, uint32_t size) {
FILE* fp = (FILE*)(file->data);
return (int32_t)fread(buffer, 1, size, fp);
}
static int32_t fs_os_file_write(fs_file_t* file, const void* buffer, uint32_t size) {
FILE* fp = (FILE*)(file->data);
return fwrite(buffer, 1, size, fp);
}
/* 构建 fs_file_t 对象的虚函数表 */
static const fs_file_vtable_t s_file_vtable = {
.read = fs_os_file_read,
.write = fs_os_file_write,
...
}
/* 构建 fs_dir_t 对象的虚函数表 */
static const fs_dir_vtable_t s_dir_vtable = {
.read = fs_os_dir_read,
...
};
2、实现 os_fs 函数
接着实现文件系统对象 fs_t,文件对象打开成功后要与上述 fs_file_vtable_t 对象挂接一起。最后实现 os_fs 函数返回全局 fs_t 对象即可,代码片段如下:
c
/* 打开文件 */
static fs_file_t* fs_os_open_file(fs_t* fs, const char* name, const char* mode) {
/* 此处使用 fopen 接口实现为例,具体请根据相关平台实现 */
fs_file_t* f = TKMEM_ZALLOC(fs_file_t);
f->vt = &s_file_vtable; /* 挂接fs_file_vtable_t对象 */
f->data = (void*)fopen(name, mode);
return f;
}
/* 打开目录 */
static fs_dir_t* fs_os_open_dir(fs_t* fs, const char* name) {
fs_dir_t* d = TKMEM_ZALLOC(fs_dir_t);
d->vt = &s_dir_vtable; /* 挂接fs_dir_vtable_t对象 */
d->data = opendir(name);
return d;
}
/* 构建 fs_t 对象:将实现的文件系统操作函数赋值给虚表中对应的函数指针 */
static const fs_t s_os_fs = {.open_file = fs_os_open_file,
.open_dir = fs_os_open_dir,
...};
/* 获取 fs_t 对象 */
fs_t* os_fs(void) {
return (fs_t*)&s_os_fs;
}
此外,在嵌入式平台中,有时没有 posix 兼容的文件系统 API,需要把一些文件系统实现包装成 awtk/src/tkc/fs.h 中的接口,此时可以直接使用 AWTK 提供的文件系统适配器 awtk-fs-adapter,目前支持的文件系统如下:
- FATFS 主要用于访问 TF card。
- SPIFFS 主要用于访问 Nor Flash。
6.2 多线程相关资源
AWTK 本身只有一个 GUI 线程,无需用到多线程相关资源,因此线程相关功能可根据项目实际需求决定是否进行移植。AWTK 中的多线程相关功能的对应的接口文件详见下表:
函数库 | 接口文件 | 说明 |
---|---|---|
thread | src/tkc/thread.h | 线程 |
mutex | src/tkc/mutex.h | 互斥锁 |
cond | src/tkc/cond.h | 条件变量 |
semaphore | src/tkc/semaphore.h | 信号量 |
需要注意的是,在应用程序中,如果需要在非 GUI 线程向主循环(GUI 线程)发送事件则必须参考本文 5.5.2 章节的内容移植互斥锁,如果在非 GUI 线程中调用 AWTK 内存管理器(awtk/src/tkc/mem.h)中的相关函数,除了需移植互斥锁之外,还需要参考本文 5.2.3 章节内容移植信号量。
下文中的示例代码均以 pthread 为例,具体代码实现请参考:awtk/platforms/pc/thread_with_pthread.c。
AWTK 提供了常见 RTOS 的多线程资源实现,具体详见 awtk/src/platforms 目录下对应平台的实现代码,用户可直接加入工程使用。
6.2.1 线程
移植 AWTK 的线程需要实现 awtk/src/tkc/thread.h 中的 _tk_thread_t 结构体以及相关接口,结构体代码如下:
c
struct _tk_thread_t {
/* 平台无关成员(移植时必须定义) */
void* args; /* 线程回调函数上下文 */
tk_thread_entry_t entry; /* 线程回调函数 */
bool_t running; /* 线程是否正在执行 */
const char* name; /* 线程的名称 */
uint32_t stack_size; /* 线程的栈大小 */
uint32_t priority; /* 线程的优先级 */
/* 平台相关成员(移植到其他平台时,请根据实际需求定义) */
pthread_t thread; /* 此处以 pthread 为例 */
};
线程相关接口说明详见下表:
接口 | 说明 | 备注 |
---|---|---|
tk_thread_create | 创建thread对象 | 保存上下文 ctx 和回调函数 entry |
tk_thread_set_name | 设置线程名称 | |
tk_thread_set_stack_size | 设置线程栈大小 | |
tk_thread_set_priority | 设置线程优先级 | 某些平台可能不支持 |
tk_thread_get_priority_from_platform | 获取平台相关的优先级 | 某些平台可能不支持 |
tk_thread_start | 启动线程 | 将 running 属性设置为 TRUE |
tk_thread_join | 等待线程退出 | 将 running 属性设置为 FALSE |
tk_thread_get_args | 获取线程的参数 | |
tk_thread_destroy | 销毁thread对象 | |
tk_thread_self | 获取当前线程的原生句柄 |
6.2.2 互斥锁
移植 AWTK 的互斥锁需要实现 awtk/src/tkc/mutex.h 中的 _tk_mutex_t 结构体以及相关接口,结构体代码如下:
c
struct _tk_mutex_t {
/* 定义一个互斥锁,请根据实际平台实现 */
pthread_mutex_t mutex; /* 此处以 pthread 为例 */
};
互斥锁相关接口详见下表:
接口 | 说明 |
---|---|
tk_mutex_create | 创建互斥锁对象 |
tk_mutex_lock | 加锁 |
tk_mutex_try_lock | 尝试加锁 |
tk_mutex_unlock | 解锁 |
tk_mutex_destroy | 销毁互斥锁对象 |
6.2.3 信号量
移植 AWTK 的信号量需要实现 awtk/src/tkc/semaphore.h 中的 _tk_semaphore_t 结构体以及相关接口,结构体代码如下:
c
struct _tk_semaphore_t {
/* 定义一个信号量,请根据实际平台实现 */
sem_t* sem; /* 此处以 sem_t 为例 */
};
信号量相关接口详见下表:
接口 | 说明 |
---|---|
tk_semaphore_create | 创建信号量对象 |
tk_semaphore_wait | 获取资源 |
tk_semaphore_post | 释放资源 |
tk_semaphore_destroy | 销毁信号量对象 |
6.2.4 条件变量
移植 AWTK 的条件变量需要实现 awtk/src/tkc/cond.h 中的 _tk_cond_t 结构体以及相关接口,结构体代码如下:
条件变量通常与互斥锁结合使用,一般来说,移植条件变量前需要先移植互斥锁。
c
struct _tk_cond_t {
/* 定义一个条件变量,请根据实际平台实现 */
pthread_cond_t cond; /* 此处以 pthread 为例 */
};
条件变量相关接口详见下表:
接口 | 说明 |
---|---|
tk_cond_create | 创建条件变量对象 |
tk_cond_wait | 等待 |
tk_cond_wait_timeout | 等待指定时间 |
tk_cond_signal | 唤醒 |
tk_cond_destroy | 销毁条件变量对象 |