From cef0c50276e542c7e815ab07a118a06b22b979de Mon Sep 17 00:00:00 2001 From: lixianjing Date: Thu, 23 Dec 2021 09:48:27 +0800 Subject: [PATCH] add aworkslp --- docs/changes.md | 3 + src/platforms/aworkslp/awtk_config.h | 142 +++++++ src/platforms/aworkslp/fs_aworks.c | 550 +++++++++++++++++++++++++ src/platforms/aworkslp/fs_os.c | 225 ++++++++++ src/platforms/aworkslp/mutex.c | 88 ++++ src/platforms/aworkslp/platform.c | 276 +++++++++++++ src/platforms/aworkslp/semaphore.c | 74 ++++ src/platforms/aworkslp/serial_helper.c | 326 +++++++++++++++ src/platforms/aworkslp/socket.c | 31 ++ src/platforms/aworkslp/thread.c | 149 +++++++ tests/fscript_test.cc | 1 - 11 files changed, 1864 insertions(+), 1 deletion(-) create mode 100644 src/platforms/aworkslp/awtk_config.h create mode 100644 src/platforms/aworkslp/fs_aworks.c create mode 100644 src/platforms/aworkslp/fs_os.c create mode 100644 src/platforms/aworkslp/mutex.c create mode 100644 src/platforms/aworkslp/platform.c create mode 100644 src/platforms/aworkslp/semaphore.c create mode 100644 src/platforms/aworkslp/serial_helper.c create mode 100644 src/platforms/aworkslp/socket.c create mode 100644 src/platforms/aworkslp/thread.c diff --git a/docs/changes.md b/docs/changes.md index 30b1fb8e1..05e810be5 100644 --- a/docs/changes.md +++ b/docs/changes.md @@ -1,5 +1,8 @@ # 最新动态 +2021/12/23 + * 增加aworkslp平台支持(感谢林福提供补丁) + 2021/12/22 * 复原被覆盖的tools/idl\_gen/README.md(感谢雨欣提供补丁) * 增加tkc/sha256.h diff --git a/src/platforms/aworkslp/awtk_config.h b/src/platforms/aworkslp/awtk_config.h new file mode 100644 index 000000000..e00291673 --- /dev/null +++ b/src/platforms/aworkslp/awtk_config.h @@ -0,0 +1,142 @@ + +/** + * File: awtk_config.h + * Author: AWTK Develop Team + * Brief: config + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2018-09-12 Li XianJing created + */ + +#ifndef AWTK_CONFIG_H +#define AWTK_CONFIG_H + +#define WITH_SOCKET 1 + +#ifndef __AWORKS_LP__ +#define __AWORKS_LP__ +#endif + +#ifndef AWORKS +#define AWORKS +#endif + +#ifndef AXIO_AWORKS +#define AXIO_AWORKS +#endif + +extern int aw_kprintf(const char* fmt, ...); +#define log_impl(format, args...) aw_kprintf(format, ##args) + +/** + * 如果出现wcsxxx之类的函数没有定义时,请定义该宏 + * + * #define WITH_WCSXXX 1 + */ +// #define WITH_WCSXXX 1 + +/** + * 如果需要配置文件或者使用data_reader/data_writer,请定义本宏。 + * + * #define WITH_DATA_READER_WRITER 1 + */ +#define WITH_DATA_READER_WRITER 1 + +/** + * 如果不需输入法,请定义本宏 + * + * #define WITH_NULL_IM 1 + */ +#define WITH_NULL_IM 1 + +/** + * 嵌入式系统有自己的main函数时,请定义本宏。 + * + */ +#define USE_GUI_MAIN 1 + +/** + * 如果支持png/jpeg图片,请定义本宏 + * + */ +// #define WITH_STB_IMAGE 1 + +/** + * 如果支持Truetype字体,请定义本宏 + * + */ +// #define WITH_STB_FONT 1 + +/** + * 如果定义本宏,使用标准的UNICODE换行算法,除非资源极为有限,请定义本宏。 + * + */ +// #define WITH_UNICODE_BREAK 1 + +/** + * 如果定义本宏,将图片解码成BGRA8888格式,否则解码成RGBA8888的格式。 + * + */ +// #define WITH_BITMAP_BGRA 1 + +/** + * 如果定义本宏,将不透明的PNG图片解码成BGR565格式,建议定义。 + * + */ +// #define WITH_BITMAP_BGR565 1 + +/** + * 如果有优化版本的memcpy函数,请定义本宏 + * + */ +#define HAS_FAST_MEMCPY 1 + +/** + * 如果系统有标准的malloc函数,请定义本宏 + * + */ +#define HAS_STD_MALLOC 1 + +/** + * 如果启用NXP PXP硬件加速,请定义本宏 + * + */ +// #define WITH_PXP_G2D 1 + +/** + * 如果启用三缓冲模式,请定义本宏,否则默认使用双缓冲模式 + * + * 注意:如果使用 tk_set_lcd_orientation 旋转屏幕,则应该注释该行, + * 使用默认的双缓冲机制,否则窗口动画可能有花屏现象 + */ +// #define WITH_THREE_FB 1 + +/** + * 如果启用VGCANVAS,而且没有OpenGL硬件加速,请定义本宏 + * + */ +// #define WITH_NANOVG_AGGE 1 + +/** + * 按新awtk加入pinyin输入法开关 + * 并关闭联想输入法,避免编译超出RT1052-AWorks上的代码段4088K + * + */ +// #define WITH_IME_PINYIN 1 +// #define WITHOUT_SUGGEST_WORDS 1 + +#ifndef __BUILDING_AWTK_LIB__ +#endif // __BUILDING_AWTK_LIB__ + +#endif /*AWTK_CONFIG_H*/ diff --git a/src/platforms/aworkslp/fs_aworks.c b/src/platforms/aworkslp/fs_aworks.c new file mode 100644 index 000000000..7a85415f7 --- /dev/null +++ b/src/platforms/aworkslp/fs_aworks.c @@ -0,0 +1,550 @@ +/** + * File: mutex.c + * Author: AWTK Develop Team + * Brief: mutex + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "aworks.h" +#include "aw_mount.h" +#include "aw_unistd.h" +#include "aw_fcntl.h" +#include "aw_fs_type.h" +#include "aw_dirent.h" +#include "aw_stat.h" +#include "aw_ioctl.h" +#include "aw_stropts.h" +#include "aw_fs_type.h" + +#include "tkc/fs.h" +#include "tkc/mem.h" +#include "tkc/path.h" +#include "tkc/utils.h" + +#ifndef tk_log_info_lf +#define tk_log_info_lf(fmt, args...) +#define tk_log_info_htlf(header, fmt, args...) +#endif + +#ifndef TKC_FS_EXE_PATH +#define TKC_FS_EXE_PATH "/lfs/bin/app/" +#endif + +#ifndef TKC_FS_TEMP_PATH +#define TKC_FS_TEMP_PATH "/lfs/tmp/" +#endif + +/*----------------------------------------------------------------------------*/ +/* 文件操作 */ +/*----------------------------------------------------------------------------*/ + +static int32_t fs_os_file_read(fs_file_t* file, void* buffer, uint32_t size) { + return_value_if_fail(file, -1); + int fd = (int)(file->data); + + return (int32_t)aw_read(fd, buffer, size); +} + +static int32_t fs_os_file_write(fs_file_t* file, const void* buffer, uint32_t size) { + return_value_if_fail(file, -1); + int fd = (int)(file->data); + + return aw_write(fd, buffer, size); +} + +static ret_t fs_os_file_seek(fs_file_t* file, int32_t offset) { + return_value_if_fail(file, RET_BAD_PARAMS); + int fd = (int)(file->data); + + return aw_lseek(fd, offset, AW_SEEK_SET) >= 0 ? RET_OK : RET_FAIL; +} + +static ret_t fs_os_file_truncate(fs_file_t* file, int32_t size) { + return_value_if_fail(file, RET_BAD_PARAMS); + int fd = (int)(file->data); + + return aw_ftruncate(fd, size) == AW_OK ? RET_OK : RET_FAIL; +} + +static ret_t fs_os_file_sync(fs_file_t* file) { + return_value_if_fail(file, RET_BAD_PARAMS); + int fd = (int)(file->data); + return aw_fsync(fd) == AW_OK ? RET_OK : RET_FAIL; +} + +static ret_t fs_os_file_close(fs_file_t* file) { + return_value_if_fail(file, RET_BAD_PARAMS); + int fd = (int)(file->data); + + aw_close(fd); + TKMEM_FREE(file); + + return RET_OK; +} +static ret_t fs_os_file_stat(fs_file_t* file, fs_stat_info_t* fst) { + return_value_if_fail(file && fst, RET_FAIL); + struct aw_stat st; + int fd = (int)(file->data); + return_value_if_fail(aw_fstat(fd, &st) == AW_OK, -1); + + memset(fst, 0, sizeof(*fst)); + fst->mode = st.st_mode; + fst->size = st.st_size; + fst->dev = st.st_dev; + fst->rdev = st.st_rdev; + + fst->dev = st.st_dev; + fst->ino = st.st_ino; + fst->mode = st.st_mode; + fst->nlink = st.st_nlink; + fst->uid = st.st_uid; + fst->gid = st.st_gid; + fst->rdev = st.st_rdev; + fst->size = st.st_size; + + fst->is_dir = AW_S_ISDIR(st.st_mode); + fst->is_reg_file = AW_S_ISREG(st.st_mode); + return RET_OK; +} + +static const fs_file_vtable_t s_fs_file_vtable_t = {.read = fs_os_file_read, + .write = fs_os_file_write, + .seek = fs_os_file_seek, + .truncate = fs_os_file_truncate, + .stat = fs_os_file_stat, + .sync = fs_os_file_sync, + .close = fs_os_file_close}; + +static fs_file_t* fs_file_create(int fd) { + fs_file_t* f = NULL; + return_value_if_fail(fd >= 0, NULL); + + f = TKMEM_ZALLOC(fs_file_t); + if (f != NULL) { + f->vt = &s_fs_file_vtable_t; + f->data = (void*)fd; + } else { + aw_close(fd); + } + + return f; +} + +#if TKC_SAVE_FIRMWARE_BY_BL + +static int32_t fs_bl_firmware_read(fs_file_t* file, void* buffer, uint32_t size) { + return_value_if_fail(!"not support!", -1); + return -1; +} + +static int32_t fs_bl_firmware_write(fs_file_t* file, const void* buffer, uint32_t size) { + return BL_AppUpdateProcess(buffer, size); +} + +static ret_t fs_bl_firmware_seek(fs_file_t* file, int32_t offset) { + return_value_if_fail(!"not support!", RET_NOT_IMPL); + return RET_OK; +} + +static ret_t fs_bl_firmware_truncate(fs_file_t* file, int32_t size) { + return_value_if_fail(!"not support!", -1); + return -1; +} + +static ret_t fs_bl_firmware_sync(fs_file_t* file) { + return_value_if_fail(!"not support!", -1); + return -1; +} + +static ret_t fs_bl_firmware_close(fs_file_t* file) { + return_value_if_fail(BL_AppUpdateEnd() == 0, RET_FAIL); + TKMEM_FREE(file); + return RET_OK; +} + +static ret_t fs_bl_firmware_stat(fs_file_t* file, fs_stat_info_t* fst) { + return_value_if_fail(!"not support!", -1); + return -1; +} + +static const fs_file_vtable_t s_fs_bl_firmware_vtable_t = { + .read = fs_bl_firmware_read, + .write = fs_bl_firmware_write, + .seek = fs_bl_firmware_seek, + .truncate = fs_bl_firmware_truncate, + .stat = fs_bl_firmware_stat, + .sync = fs_bl_firmware_sync, + .close = fs_bl_firmware_close, +}; + +static fs_file_t* fs_bl_firmware_create(void) { + fs_file_t* f = NULL; + int ret; + + f = TKMEM_ZALLOC(fs_file_t); + if (f != NULL) { + f->vt = &s_fs_bl_firmware_vtable_t; + f->data = NULL; + ret = BL_AppUpdateStart(TKC_FIRMWARE_PATH); + if (ret != 0) { + TKMEM_FREE(f); + return_value_if_fail(!"BL_AppUpdateStart() failed", NULL); + } + } + return f; +} +#endif /* TKC_SAVE_FIRMWARE_BY_BL */ + +static fs_file_t* fs_os_open_file(fs_t* fs, const char* name, const char* mode) { + (void)fs; + return_value_if_fail(name && mode, NULL); + int oflag = 0; + fs_file_t* file; + + if (strchr(mode, '+')) { + if (strchr(mode, 'r')) { + oflag |= AW_O_RDWR; + } else if (strchr(mode, 'w')) { + oflag |= AW_O_RDWR | AW_O_CREAT | AW_O_TRUNC; + } else if (strchr(mode, 'a')) { +#if 0 + oflag |= AW_O_RDWR | AW_O_CREAT | AW_O_APPEND; +#else + /* lfs bug:带有 APPEND 标志,则每次写都从文件尾开始写,seek 就无效了,因此这里不带 append 标志,创建完后再 seek 一次 */ + oflag |= AW_O_RDWR | AW_O_CREAT; +#endif + } + } else { + if (strchr(mode, 'r')) { + oflag |= AW_O_RDONLY; + } else if (strchr(mode, 'w')) { + oflag |= AW_O_WRONLY | AW_O_CREAT | AW_O_TRUNC; + } else if (strchr(mode, 'a')) { +#if 0 + oflag |= AW_O_RDWR | AW_O_CREAT | AW_O_APPEND; +#else + /* lfs bug:带有 APPEND 标志,则每次写都从文件尾开始写,seek 就无效了,因此这里不带 append 标志,创建完后再 seek 一次 */ + oflag |= AW_O_RDWR | AW_O_CREAT; +#endif + } + } + +#if TKC_SAVE_FIRMWARE_BY_BL + if (tk_str_eq(TKC_FIRMWARE_PATH, name)) { + file = fs_bl_firmware_create(); + } + return file; +#endif /* TKC_SAVE_FIRMWARE_BY_BL */ + + file = fs_file_create(aw_open(name, oflag, 0777)); + if (file) { + if (strchr(mode, 'a')) { + int fd = (int)(file->data); + aw_lseek(fd, 0, AW_SEEK_END); + } + } + return file; +} + +static ret_t fs_os_remove_file(fs_t* fs, const char* name) { + (void)fs; + return_value_if_fail(name, RET_BAD_PARAMS); + + return aw_unlink(name) == AW_OK ? RET_OK : RET_FAIL; +} + +static bool_t fs_os_file_exist(fs_t* fs, const char* name) { + (void)fs; + return_value_if_fail(name, FALSE); + + struct aw_stat st; + return (aw_stat(name, &st) == 0 && AW_S_ISREG(st.st_mode)); +} + +static bool_t fs_os_file_rename(fs_t* fs, const char* name, const char* new_name) { + (void)fs; + return_value_if_fail(name && new_name, FALSE); + + return (aw_rename(name, new_name) == AW_OK); +} + +static ret_t fs_os_stat(fs_t* fs, const char* name, fs_stat_info_t* fst) { + struct aw_stat st; + return_value_if_fail(fs && fst && name, RET_FAIL); + return_value_if_fail(aw_stat(name, &st) == AW_OK, -1); + + memset(fst, 0, sizeof(*fst)); + fst->mode = st.st_mode; + fst->size = st.st_size; + fst->dev = st.st_dev; + fst->rdev = st.st_rdev; + + fst->dev = st.st_dev; + fst->ino = st.st_ino; + fst->mode = st.st_mode; + fst->nlink = st.st_nlink; + fst->uid = st.st_uid; + fst->gid = st.st_gid; + fst->rdev = st.st_rdev; + fst->size = st.st_size; + + fst->is_dir = AW_S_ISDIR(st.st_mode); + fst->is_reg_file = AW_S_ISREG(st.st_mode); + return RET_OK; +} + +/*----------------------------------------------------------------------------*/ +/* 文件夹操作 */ +/*----------------------------------------------------------------------------*/ + +struct fs_dir_ex { + fs_dir_t dir; + char dir_name[MAX_PATH + 1]; +}; + +static ret_t fs_os_dir_read(fs_dir_t* dir, fs_item_t* item) { + return_value_if_fail(dir && dir->data && item, RET_BAD_PARAMS); + char item_path[MAX_PATH]; + struct aw_dirent* entry; + struct aw_dir* d = (struct aw_dir*)(dir->data); + return_value_if_fail(aw_readdir(d, &entry) == AW_OK, RET_FAIL); + + memset(item, 0x00, sizeof(fs_item_t)); + if (entry != NULL) { + item_path[0] = '\0'; + strncat(item_path, ((struct fs_dir_ex*)dir)->dir_name, MAX_PATH); + strncat(item_path, "/", MAX_PATH); + strncat(item_path, entry->d_name, MAX_PATH); + + struct aw_stat st; + return_value_if_fail(aw_stat(item_path, &st) == AW_OK, RET_FAIL); + + item->is_dir = AW_S_ISDIR(st.st_mode); + item->is_reg_file = AW_S_ISREG(st.st_mode); + tk_strncpy(item->name, entry->d_name, MAX_PATH); + return RET_OK; + } else { + return RET_FAIL; + } +} + +static ret_t fs_os_dir_rewind(fs_dir_t* dir) { + return_value_if_fail(!"fs_os_dir_rewind not supported yet", RET_BAD_PARAMS); + return RET_NOT_IMPL; +} + +static ret_t fs_os_dir_close(fs_dir_t* dir) { + return_value_if_fail(dir && dir->data, RET_BAD_PARAMS); + struct aw_dir* d = (struct aw_dir*)dir->data; + + aw_closedir(d); + TKMEM_FREE(d); + TKMEM_FREE(dir); + + return RET_OK; +} + +static const fs_dir_vtable_t s_fs_dir_vtable_t = { + .read = fs_os_dir_read, .rewind = fs_os_dir_rewind, .close = fs_os_dir_close}; + +static fs_dir_t* fs_dir_create(struct aw_dir* dir, const char* dir_name) { + fs_dir_t* d = NULL; + return_value_if_fail(dir != NULL, NULL); + + struct fs_dir_ex* d_ex = TKMEM_ZALLOC(struct fs_dir_ex); + if (d_ex != NULL) { + d = &d_ex->dir; + d->vt = &s_fs_dir_vtable_t; + d->data = dir; + tk_strncpy(d_ex->dir_name, dir_name, MAX_PATH); + } else { + aw_closedir(dir); + TKMEM_FREE(dir); + } + + return d; +} + +static ret_t fs_os_create_dir(fs_t* fs, const char* name) { + return aw_mkdir(name, AW_S_IRWXU | AW_S_IRWXG | AW_S_IRWXO) == 0 ? RET_OK : RET_FAIL; +} + +static fs_dir_t* fs_os_open_dir(fs_t* fs, const char* name) { + struct aw_dir* dir = TKMEM_ZALLOC(struct aw_dir); + return_value_if_fail(aw_opendir(dir, name) == AW_OK, NULL); + return fs_dir_create(dir, name); +} + +static ret_t fs_os_remove_dir(fs_t* fs, const char* name) { + return aw_rmdir(name) == AW_OK ? RET_OK : RET_FAIL; +} + +static bool_t fs_os_dir_exist(fs_t* fs, const char* name) { + struct aw_stat st; + return (aw_stat(name, &st) == AW_OK && AW_S_ISDIR(st.st_mode)); +} + +static ret_t fs_os_dir_rename(fs_t* fs, const char* name, const char* new_name) { + return (aw_rename(name, new_name) == AW_OK) ? RET_OK : RET_FAIL; +} + +/*----------------------------------------------------------------------------*/ +/* 文件系统操作 */ +/*----------------------------------------------------------------------------*/ + +static int32_t fs_os_get_file_size(fs_t* fs, const char* name) { + struct aw_stat st; + + return_value_if_fail(aw_stat(name, &st) == AW_OK, -1); + return st.st_size; +} + +static ret_t fs_os_get_disk_info(fs_t* fs, const char* volume, int32_t* free_kb, + int32_t* total_kb) { + (void)fs; + return_value_if_fail(free_kb && total_kb, RET_BAD_PARAMS); + return_value_if_fail(!"fs_os_get_disk_info not supported yet", RET_BAD_PARAMS); + + *free_kb = 0; + *total_kb = 0; + return RET_NOT_IMPL; +} + +static ret_t fs_os_get_exe(fs_t* fs, char path[MAX_PATH + 1]) { + (void)fs; + + tk_strcpy(path, TKC_FS_EXE_PATH); + if (!path_exist(path)) { + fs_create_dir_r(os_fs(), path); + tk_log_info_lf("create dir '%s'", path); + } + return_value_if_fail(path_exist(path), RET_FAIL); + + return RET_OK; +} + +static ret_t fs_os_get_cwd(fs_t* fs, char path[MAX_PATH + 1]) { + (void)fs; + return_value_if_fail(path, RET_BAD_PARAMS); + + *path = '\0'; + // return aw_getcwd(path, MAX_PATH) != NULL ? RET_OK : RET_FAIL; + return RET_OK; +} + +static ret_t fs_os_get_temp_path(fs_t* fs, char path[MAX_PATH + 1]) { + tk_strcpy(path, TKC_FS_TEMP_PATH); + if (!path_exist(path)) { + fs_create_dir_r(os_fs(), path); + tk_log_info_lf("create dir '%s'", path); + } + return_value_if_fail(path_exist(path), RET_FAIL); + return RET_OK; +} +/*----------------------------------------------------------------------------*/ +static const fs_t s_os_fs = { + .open_file = fs_os_open_file, + .remove_file = fs_os_remove_file, + .file_exist = fs_os_file_exist, + .file_rename = fs_os_file_rename, + .stat = fs_os_stat, + + .create_dir = fs_os_create_dir, + .open_dir = fs_os_open_dir, + .remove_dir = fs_os_remove_dir, + .dir_exist = fs_os_dir_exist, + .dir_rename = fs_os_dir_rename, + + .get_file_size = fs_os_get_file_size, + .get_disk_info = fs_os_get_disk_info, + .get_cwd = fs_os_get_cwd, + .get_exe = fs_os_get_exe, + .get_temp_path = fs_os_get_temp_path, +}; + +#define __MAKE_SYSFILE_NAME "~systemmkiffd.reserved" +#define __LFFS_DEVNAME "/dev/is25lpx_partition_1" + +#define __LFS_DEVNAME "/dev/is25lpx_partition_0" + +fs_t* fs_aworks_create(const char* mnt) { + int ret; + struct aw_fs_format_arg fmt = {"awdisk", 0, 1}; + struct aw_stat file_stat; + char stmp[64]; + memset(stmp, 0, sizeof(stmp)); + + if (tk_str_eq("/lffs", mnt)) { + aw_umount("/lffs", 0); + ret = aw_mount("/lffs", __LFFS_DEVNAME, AW_LFFS_TYPE_NAME, 0, NULL); + if (ret == 0) { + tk_str_append(stmp, sizeof(stmp), mnt); + tk_str_append(stmp, sizeof(stmp), "/" __MAKE_SYSFILE_NAME); + ret = aw_stat(stmp, &file_stat); + } + if (ret != 0) { + aw_umount("/lffs", 0); + aw_make_fs(__LFFS_DEVNAME, AW_LFFS_TYPE_NAME, &fmt); + ret = aw_mount("/lffs", __LFFS_DEVNAME, AW_LFFS_TYPE_NAME, 0, NULL); + goto_error_if_fail(ret == 0); + ret = aw_create("/lffs/" __MAKE_SYSFILE_NAME, AW_S_IRWXU | AW_S_IRWXG | AW_S_IRWXO); + goto_error_if_fail(ret == 0); + } + } else if (tk_str_eq("/lfs", mnt)) { + ret = aw_mount(mnt, __LFS_DEVNAME, AW_LITTLEFS_TYPE_NAME, 0, NULL); + if (ret != 0) { + aw_umount(mnt, 0); + ret = aw_make_fs(__LFS_DEVNAME, AW_LITTLEFS_TYPE_NAME, &fmt); + if (ret != AW_OK) { + ret = aw_make_fs(__LFS_DEVNAME, AW_LITTLEFS_TYPE_NAME, NULL); + goto_error_if_fail(ret == 0); + } + ret = aw_mount(mnt, __LFS_DEVNAME, AW_LITTLEFS_TYPE_NAME, 0, NULL); + goto_error_if_fail(ret == 0); + } + } else if (tk_str_eq("/dev", mnt)) { + return &s_os_fs; + } else { + return_value_if_fail(!"Not support the mnt!", NULL); + } + return &s_os_fs; + +error: + aw_umount(mnt, 0); + return NULL; +} + +/*----------------------------------------------------------------------------*/ +#if defined(UTEST_ENABLE) +void fs_aworks_utest(void) { + char* p; + uint32_t sz; + if (!dir_exist("/lfs/test_dir")) { + fs_create_dir(os_fs(), "/lfs/test_dir"); + } + ENSURE(file_write("/lfs/test_dir/tkc_test", "abc123456", tk_strlen("abc123456") + 1) == RET_OK); + p = file_read("/lfs/test_dir/tkc_test", &sz); + ENSURE(p && sz >= tk_strlen("abc123456") + 1 && + tk_str_eq_with_len(p, "abc123456", tk_strlen("abc123456") + 1)); + TKMEM_FREE(p); + + tk_log_info_htlf("[UTEST]", "test R/W \"/lfs\" pass."); +} +#else +void fs_aworks_utest(void) { +} +#endif diff --git a/src/platforms/aworkslp/fs_os.c b/src/platforms/aworkslp/fs_os.c new file mode 100644 index 000000000..b4866b5b4 --- /dev/null +++ b/src/platforms/aworkslp/fs_os.c @@ -0,0 +1,225 @@ +/** + * File: mutex.c + * Author: AWTK Develop Team + * Brief: mutex + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "tkc/fs.h" +#include "tkc/mem.h" +#include "tkc/utils.h" +#include "tkc/str_str.h" + +#define FS_REG_MAX 6 + +static str_str_t s_items[FS_REG_MAX + 1]; + +static const char* str_str_value_with_len(const str_str_t* items, const char* name) { + const str_str_t* iter = items; + uint32_t len; + return_value_if_fail(items != NULL && name != NULL, NULL); + + while (iter->name != NULL) { + len = tk_strlen(iter->name); + if (tk_str_eq_with_len(iter->name, name, len)) { + if (name[len] == '/' || name[len] == '\0') { + return iter->value; + } + } + + iter++; + } + + return NULL; +} + +/*----------------------------------------------------------------------------*/ + +static fs_file_t* fs_os_open_file(fs_t* fs, const char* name, const char* mode) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, NULL); + return rfs->open_file(rfs, name, mode); +} + +static ret_t fs_os_remove_file(fs_t* fs, const char* name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->remove_file(rfs, name); +} + +static bool_t fs_os_file_exist(fs_t* fs, const char* name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, FALSE); + return rfs->file_exist(rfs, name); +} + +static ret_t fs_os_file_rename(fs_t* fs, const char* name, const char* new_name) { + (void)fs; + fs_t* rfs = NULL; + + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, RET_BAD_PARAMS); + if ((fs_t*)str_str_value_with_len(s_items, new_name) != rfs) { + return_value_if_fail(rfs, RET_BAD_PARAMS); + } + return rfs->file_rename(rfs, name, new_name); +} + +static ret_t fs_os_stat(fs_t* fs, const char* name, fs_stat_info_t* fst) { + fs_t* rfs = NULL; + + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->stat(rfs, name, fst); +} + +/*----------------------------------------------------------------------------*/ +static ret_t fs_os_create_dir(fs_t* fs, const char* name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->create_dir(rfs, name); +} + +static fs_dir_t* fs_os_open_dir(fs_t* fs, const char* name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, NULL); + return rfs->open_dir(rfs, name); +} + +static ret_t fs_os_remove_dir(fs_t* fs, const char* name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->remove_dir(rfs, name); +} + +static bool_t fs_os_dir_exist(fs_t* fs, const char* name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, FALSE); + if (strrchr(name, '/') == name) { + return TRUE; + } + return rfs->dir_exist(rfs, name); +} + +static ret_t fs_os_dir_rename(fs_t* fs, const char* name, const char* new_name) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, FALSE); + if ((fs_t*)str_str_value_with_len(s_items, new_name) != rfs) { + return_value_if_fail(rfs, FALSE); + } + return rfs->dir_rename(rfs, name, new_name); +} + +/*----------------------------------------------------------------------------*/ + +static int32_t fs_os_get_file_size(fs_t* fs, const char* name) { + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, name); + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->get_file_size(rfs, name); +} + +static ret_t fs_os_get_disk_info(fs_t* fs, const char* volume, int32_t* free_kb, + int32_t* total_kb) { + (void)fs; + fs_t* rfs = NULL; + rfs = (fs_t*)str_str_value_with_len(s_items, volume); + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->get_disk_info(rfs, volume, free_kb, total_kb); +} + +static ret_t fs_os_get_exe(fs_t* fs, char path[MAX_PATH + 1]) { + fs_t* rfs = s_items[0].value; + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->get_exe(rfs, path); +} + +static ret_t fs_os_get_cwd(fs_t* fs, char path[MAX_PATH + 1]) { + (void)fs; + return_value_if_fail(path, RET_BAD_PARAMS); + + *path = '\0'; + return RET_NOT_IMPL; +} + +static ret_t fs_os_get_temp_path(fs_t* fs, char path[MAX_PATH + 1]) { + fs_t* rfs = s_items[0].value; + return_value_if_fail(rfs, RET_BAD_PARAMS); + return rfs->get_temp_path(rfs, path); +} +/*----------------------------------------------------------------------------*/ +typedef fs_t* (*fs_create_t)(const char* mnt); + +ret_t fs_os_register(const char* mnt_name, fs_t* (*create)(const char*)) { + return_value_if_fail(mnt_name && create, RET_BAD_PARAMS); + return_value_if_fail(mnt_name[0] == '/', RET_BAD_PARAMS); + int i; + fs_t* fs = create(mnt_name); + return_value_if_fail(fs, RET_BAD_PARAMS); + + for (i = 0; i < FS_REG_MAX; i++) { + if (s_items[i].name == NULL) { + s_items[i].name = tk_strdup(mnt_name); + s_items[i].value = (char*)fs; + return RET_OK; + } + } + return_value_if_fail(!"fs register num over FS_REG_MAX!", RET_OOM); + return RET_OOM; +} + +/*----------------------------------------------------------------------------*/ + +static const fs_t s_os_fs = { + .open_file = fs_os_open_file, + .remove_file = fs_os_remove_file, + .file_exist = fs_os_file_exist, + .file_rename = fs_os_file_rename, + .stat = fs_os_stat, + + .create_dir = fs_os_create_dir, + .open_dir = fs_os_open_dir, + .remove_dir = fs_os_remove_dir, + .dir_exist = fs_os_dir_exist, + .dir_rename = fs_os_dir_rename, + + .get_file_size = fs_os_get_file_size, + .get_disk_info = fs_os_get_disk_info, + .get_cwd = fs_os_get_cwd, + .get_exe = fs_os_get_exe, + .get_temp_path = fs_os_get_temp_path, +}; + +fs_t* os_fs(void) { + return (fs_t*)&s_os_fs; +} diff --git a/src/platforms/aworkslp/mutex.c b/src/platforms/aworkslp/mutex.c new file mode 100644 index 000000000..2eef480e2 --- /dev/null +++ b/src/platforms/aworkslp/mutex.c @@ -0,0 +1,88 @@ +/** + * File: mutex.c + * Author: AWTK Develop Team + * Brief: mutex + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "aw_sem.h" +#include "aw_mem.h" +#include "tkc/mutex.h" + +struct _tk_mutex_t { + AW_MUTEX_DECL(__lock); +}; + +//static tk_mutex_t s_tk_mutex_null; + +tk_mutex_t* tk_mutex_create(void) { + tk_mutex_t* mutex = (tk_mutex_t*)aw_mem_alloc(sizeof(tk_mutex_t)); + + if (mutex) { + memset(mutex, 0, sizeof(tk_mutex_t)); + if (NULL == AW_MUTEX_INIT(mutex->__lock, AW_SEM_INVERSION_SAFE)) { + aw_mem_free(mutex); + return NULL; + } + } + + return mutex; +} + +ret_t tk_mutex_lock(tk_mutex_t* mutex) { + assert(mutex); + aw_err_t err = AW_MUTEX_LOCK(mutex->__lock, AW_SEM_WAIT_FOREVER); + + switch (err) { + case AW_OK: + return RET_OK; + default: + return RET_FAIL; + } +} + +ret_t tk_mutex_try_lock(tk_mutex_t* mutex) { + assert(mutex); + aw_err_t err = AW_MUTEX_LOCK(mutex->__lock, 0); + + switch (err) { + case AW_OK: + return RET_OK; + default: + return RET_FAIL; + } +} + +ret_t tk_mutex_unlock(tk_mutex_t* mutex) { + assert(mutex); + aw_err_t err = AW_MUTEX_UNLOCK(mutex->__lock); + + switch (err) { + case AW_OK: + return RET_OK; + default: + return RET_FAIL; + } +} + +ret_t tk_mutex_destroy(tk_mutex_t* mutex) { + assert(mutex); + AW_MUTEX_TERMINATE(mutex->__lock); + + aw_mem_free(mutex); + return RET_OK; +} diff --git a/src/platforms/aworkslp/platform.c b/src/platforms/aworkslp/platform.c new file mode 100644 index 000000000..c581a12a8 --- /dev/null +++ b/src/platforms/aworkslp/platform.c @@ -0,0 +1,276 @@ +/** + * File: platform.c + * Author: AWTK Develop Team + * Brief: platform dependent function of aworks + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * this program is distributed in the hope that it will be useful, + * but without any warranty; without even the implied warranty of + * merchantability or fitness for a particular purpose. see the + * license file for more details. + * + */ + +/** + * history: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "aworks.h" +#include "aw_system.h" +#include "aw_delay.h" +#include "aw_mem.h" +#include "aw_time.h" + +#include "tkc/mem.h" +#include "tkc/date_time.h" +#include "tkc/fscript.h" +#include "tkc/fs.h" +#include "tkc/data_reader_factory.h" +#include "tkc/data_reader_file.h" +#include "tkc/data_reader_mem.h" +#include "tkc/data_writer_factory.h" +#include "tkc/data_writer_file.h" +#include "tkc/path.h" + +#ifndef tk_log_info_lf +#define tk_log_info_lf(fmt, args...) +#define tk_log_info_htlf(header, fmt, args...) +#define tk_log_warn_htlf(header, fmt, args...) +#endif + +extern ret_t fs_os_register(const char* mnt_name, fs_t* (*create)(const char*)); +extern fs_t* fs_aworks_create(const char* mnt); +static void platform_test(void); + +static ret_t date_time_get_now_impl(date_time_t* dt) { + aw_err_t ret; + aw_tm_t t; + ret = aw_local_tm_get(&t); + + if (ret == AW_OK) { + dt->second = t.tm_sec; + dt->minute = t.tm_min; + dt->hour = t.tm_hour; + dt->day = t.tm_mday; + dt->month = t.tm_mon + 1; + dt->year = t.tm_year + 1900; + dt->wday = t.tm_wday; + } else { + dt->second = 0; + dt->minute = 0; + dt->hour = 0; + dt->day = 11; + dt->month = 11; + dt->year = 2018; + dt->wday = 0; + } + + return RET_OK; +} + +#ifndef HAS_STD_MALLOC +#define TK_MEM_SIZE 1 * 1024 * 1024 + +static ret_t mem_init(void) { + uint32_t* mem = (uint32_t*)aw_mem_alloc(TK_MEM_SIZE); + assert(mem != NULL); + + tk_mem_init(mem, TK_MEM_SIZE); +} +#else +#define mem_init() +#endif + +uint64_t get_time_ms64() { + return aw_sys_tick_get(); +} + +void sleep_ms(uint32_t ms) { + aw_mdelay(ms); +} + +void perror(const char* a) { +} + +static ret_t fs_func_memdump(tk_object_t* obj, fscript_args_t* args, value_t* result) { + tk_mem_dump(); + value_set_bool(result, 1); + return RET_OK; +} + +static ret_t writer_reader_init(void) { + data_reader_factory_t* reader_factory = data_reader_factory_create(); + data_writer_factory_t* writer_factory = data_writer_factory_create(); + + data_reader_factory_set(reader_factory); + // data_reader_factory_register(reader_factory, "asset", data_reader_asset_create); + data_reader_factory_register(reader_factory, "mem", data_reader_mem_create); + data_reader_factory_register(reader_factory, "file", data_reader_file_create); + data_writer_factory_set(writer_factory); + data_writer_factory_register(writer_factory, "file", data_writer_file_create); + + return RET_OK; +} + +ret_t platform_prepare(void) { + static bool_t inited = FALSE; + char path[MAX_PATH + 1]; + + if (inited) { + return RET_OK; + } + inited = TRUE; + + mem_init(); + date_time_set_impl(date_time_get_now_impl); + writer_reader_init(); + fs_os_register("/lfs", fs_aworks_create); /* littlefs */ + fscript_register_func("memdump", fs_func_memdump); + + fs_get_exe(os_fs(), path); + tk_log_info_lf("fs_get_exe('%s').", path); + + fs_get_temp_path(os_fs(), path); + tk_log_info_lf("fs_get_temp_path('%s').", path); + + path_app_root(path); + tk_log_info_lf("path_app_root('%s').", path); + + tk_log_info_lf("done."); + + platform_test(); + return RET_OK; +} + +/*****************************************************************************/ +#if defined(UTEST_ENABLE) && 1 + +#include "tkc/thread.h" +#include "tkc/semaphore.h" +#include "tkc/mutex.h" +#include "tkc/fs.h" +#include "tkc/str.h" + +typedef struct { + void* args; + int run; +} thread_ctx_t; + +static void* task_entry(void* args) { + int i = 5; + static int chk_pri = 1; + if (chk_pri == 1) { + ENSURE(tk_str_eq_with_len("high", (const char*)args, 4)); + chk_pri++; + } + while (i-- > 0) { + sleep_ms(1000); + tk_log_info_htlf("[UTEST]", "task %s execute.", (char*)args); + } + return NULL; +} + +static void platform_test(void) { +#ifdef HAS_STD_MALLOC + if (1) { + void* p = malloc(8); + tk_log_info_htlf("[UTEST]", "test_str: step1 %p", p); + ENSURE(p); + tk_snprintf(p, 8, "abc123"); + p = realloc(p, 16); + tk_log_info_htlf("[UTEST]", "test_str: step1"); + ENSURE(p); + ENSURE(tk_str_cmp(p, "abc123") == 0); + free(p); + } +#endif + + if (1) { + uint64_t s = time_now_ms(); + tk_log_info_htlf("[TEST]", "sleep_ms: start %u ms", (unsigned int)s); + sleep_ms(1050); + tk_log_info_htlf("[TEST]", "sleep_ms: stop %u ms (%u)", (unsigned int)time_now_ms(), + (unsigned int)(time_now_ms() - s)); + ENSURE((time_now_ms() - s) >= 1020 && (time_now_ms() - s) <= 1080); + } + + if (1) { + tk_mutex_t* p = tk_mutex_create(); + ENSURE(tk_mutex_lock(p) == RET_OK); + ENSURE(tk_mutex_try_lock(p) == RET_OK); + ENSURE(tk_mutex_lock(p) == RET_OK); + + ENSURE(tk_mutex_unlock(p) == RET_OK); + ENSURE(tk_mutex_unlock(p) == RET_OK); + ENSURE(tk_mutex_unlock(p) == RET_OK); + + tk_mutex_destroy(p); + } + if (1) { + tk_semaphore_t* p = tk_semaphore_create(3, NULL); + + tk_log_info_htlf("[TEST]", "tk_semaphore_t: start time %u ms", (unsigned int)time_now_ms()); + ENSURE(tk_semaphore_wait(p, 1000) == RET_OK); + ENSURE(tk_semaphore_wait(p, 1000) == RET_OK); + ENSURE(tk_semaphore_wait(p, 1000) == RET_OK); + ENSURE(tk_semaphore_wait(p, 1000) != RET_OK); + + tk_log_info_htlf("[TEST]", "tk_semaphore_t: locked time %u ms", (unsigned int)time_now_ms()); + ENSURE(tk_semaphore_post(p) == RET_OK); + ENSURE(tk_semaphore_post(p) == RET_OK); + ENSURE(tk_semaphore_post(p) == RET_OK); + tk_log_info_htlf("[TEST]", "tk_semaphore_t: stop time %u ms", (unsigned int)time_now_ms()); + + tk_semaphore_destroy(p); + } + if (1) { + tk_thread_t* p = tk_thread_create(task_entry, "low_t1"); + tk_thread_t* p1 = tk_thread_create(task_entry, "high_t2"); + ENSURE(p && p1); + + tk_log_info_htlf("[TEST]", "tk_thread: start %u ms ", (unsigned int)time_now_ms()); + ENSURE(tk_thread_set_priority(p1, tk_thread_get_priority_from_platform( + TK_THREAD_PRIORITY_BELOW_NORAML)) == RET_OK); + ENSURE(tk_thread_start(p) == RET_OK); + + tk_log_info_htlf("[TEST]", "tk_thread: start %u ms ", (unsigned int)time_now_ms()); + ENSURE(tk_thread_set_priority(p1, tk_thread_get_priority_from_platform( + TK_THREAD_PRIORITY_ABOVE_NORAML)) == RET_OK); + ENSURE(tk_thread_start(p1) == RET_OK); + + tk_log_info_htlf("[TEST]", "task startup:"); + sleep_ms(3050); + + tk_thread_join(p); + tk_thread_destroy(p); + tk_log_info_htlf("[TEST]", "tk_thread: stop %u ms ", (unsigned int)time_now_ms()); + + tk_thread_join(p1); + tk_thread_destroy(p1); + tk_log_info_htlf("[TEST]", "tk_thread: stop %u ms ", (unsigned int)time_now_ms()); + } + + if (1) { + char* p; + uint32_t sz; + if (!dir_exist("/lfs/test_dir")) { + fs_create_dir(os_fs(), "/lfs/test_dir"); + } + ENSURE(file_write("/lfs/test_dir/tkc_test", "abc123456", tk_strlen("abc123456") + 1) == RET_OK); + p = file_read("/lfs/test_dir/tkc_test", &sz); + ENSURE(p && sz >= tk_strlen("abc123456") + 1 && + tk_str_eq_with_len(p, "abc123456", tk_strlen("abc123456") + 1)); + TKMEM_FREE(p); + } + + tk_log_info_htlf("[UTEST]", "pass."); +} +#else +static void platform_test(void) { + tk_log_info_htlf("[UTEST]", "nothing."); +} +#endif diff --git a/src/platforms/aworkslp/semaphore.c b/src/platforms/aworkslp/semaphore.c new file mode 100644 index 000000000..db04aa093 --- /dev/null +++ b/src/platforms/aworkslp/semaphore.c @@ -0,0 +1,74 @@ +/** + * File: semaphore.c + * Author: AWTK Develop Team + * Brief: semaphore + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "aw_sem.h" +#include "aw_mem.h" +#include "tkc/semaphore.h" + +struct _tk_semaphore_t { + AW_SEMC_DECL(__sem); +}; + +tk_semaphore_t* tk_semaphore_create(uint32_t value, const char* name) { + tk_semaphore_t* semaphore = (tk_semaphore_t*)aw_mem_alloc(sizeof(tk_semaphore_t)); + + if (semaphore) { + memset(semaphore, 0, sizeof(tk_semaphore_t)); + if (NULL == AW_SEMC_INIT(semaphore->__sem, value, AW_SEM_Q_FIFO)) { + aw_mem_free(semaphore); + return NULL; + } + } + + return semaphore; +} + +ret_t tk_semaphore_wait(tk_semaphore_t* semaphore, uint32_t timeout_ms) { + assert(semaphore); + aw_err_t err = AW_SEMC_TAKE(semaphore->__sem, timeout_ms); + + switch (err) { + case AW_OK: + return RET_OK; + default: + return RET_FAIL; + } +} + +ret_t tk_semaphore_post(tk_semaphore_t* semaphore) { + assert(semaphore); + aw_err_t err = AW_SEMC_GIVE(semaphore->__sem); + + switch (err) { + case AW_OK: + return RET_OK; + default: + return RET_FAIL; + } +} + +ret_t tk_semaphore_destroy(tk_semaphore_t* semaphore) { + assert(semaphore); + AW_SEMC_TERMINATE(semaphore->__sem); + + aw_mem_free(semaphore); + return RET_OK; +} diff --git a/src/platforms/aworkslp/serial_helper.c b/src/platforms/aworkslp/serial_helper.c new file mode 100644 index 000000000..ace74b579 --- /dev/null +++ b/src/platforms/aworkslp/serial_helper.c @@ -0,0 +1,326 @@ +/** + * File: serial_helper.c + * Author: AWTK Develop Team + * Brief: serial helper functions + * + * Copyright (c) 2019 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2019-09-11 Li XianJing created + * + */ + +/* + *the following code adapted from: https://github.com/wjwwood/serial/tree/master/src/impl + * + * Copyright 2012 William Woodall and John Harrison + * + * Additional Contributors: Christopher Baker @bakercp + */ + +#include "tkc/mem.h" +#include "tkc/wstr.h" +#include "tkc/thread.h" +#include "tkc/socket_pair.h" +#include "tkc/socket_helper.h" +#include "streams/serial/serial_helper.h" + +#ifdef __AWORKS_LP__ + +#include "aworks.h" +#include "aw_stropts.h" +#include "aw_fcntl.h" +#include "aw_unistd.h" + +#include "aw_serial.h" +#include "tkc/ring_buffer.h" +#include "tkc/darray.h" + +static darray_t* s_darray = NULL; + +typedef struct { + tk_thread_t* thread; + serial_handle_t handle; + bool_t broken; + ring_buffer_t* rb; + bool_t is_usb2uart; +} serial_dev_prv_t; + +static int da_serial_cmp(const void* a, const void* b) { + serial_dev_prv_t* pa = a; + if (pa->handle == b) { + return 0; + } + return -1; +} + +static ret_t da_serial_destroy(void* data) { + serial_dev_prv_t* p_this = data; + + if (p_this->thread) { + p_this->broken = TRUE; + ENSURE(tk_thread_join(p_this->thread) == RET_OK); + tk_thread_destroy(p_this->thread); + } + + ring_buffer_destroy(p_this->rb); + TKMEM_FREE(p_this); + return RET_OK; +} + +static void* thread_serial_recv(void* args) { + serial_dev_prv_t* p_this = args; + int32_t cnt = 0; + int fd = serial_handle_get_fd(p_this->handle); + uint8_t buff[64]; + ENSURE(p_this && fd >= 0); + + while (!p_this->broken) { + cnt = aw_read(fd, buff, sizeof(buff)); + if (cnt > 0) { + ring_buffer_write_len(p_this->rb, buff, cnt); + } else { + sleep_ms(10); + } + } + return NULL; +} + +int serial_handle_get_fd(serial_handle_t handle) { + return handle->dev; +} + +serial_dev_t serial_handle_get_dev(serial_handle_t handle) { + return handle->dev; +} + +serial_handle_t serial_open(const char* port) { + serial_dev_prv_t* p_this = TKMEM_ZALLOC(serial_dev_prv_t); + serial_handle_t handle = TKMEM_ZALLOC(serial_info_t); + return_value_if_fail(p_this && handle != NULL && port != NULL && *port != '\0', NULL); + handle->dev = aw_open(port, AW_O_RDWR, 0); + return_value_if_fail(handle, NULL); + + if (handle->dev < 0) { + TKMEM_FREE(p_this); + TKMEM_FREE(handle); + return_value_if_fail(FALSE, NULL); + } + + memset(p_this, 0, sizeof(serial_dev_prv_t)); + p_this->handle = handle; + p_this->rb = ring_buffer_create(256, 4096); + ENSURE(p_this->rb); + + if (strstr(port, "USB")) { + p_this->is_usb2uart = TRUE; + } + + if (!s_darray) { + s_darray = darray_create(5, da_serial_destroy, da_serial_cmp); + ENSURE(s_darray); + } + ENSURE(darray_push(s_darray, p_this) == RET_OK); + + return handle; +} + +ret_t serial_iflush(serial_handle_t handle) { + int fd = serial_handle_get_fd(handle); + return aw_ioctl(fd, AW_FIORFLUSH, NULL) == 0 ? RET_OK : RET_FAIL; +} + +ret_t serial_oflush(serial_handle_t handle) { + int fd = serial_handle_get_fd(handle); + serial_dev_prv_t* p_this = darray_find(s_darray, handle); + return_value_if_fail(p_this, RET_FAIL); + ring_buffer_reset(p_this->rb); + return aw_ioctl(fd, AW_FIOWFLUSH, NULL) == 0 ? RET_OK : RET_FAIL; +} + +ret_t serial_wait_for_data(serial_handle_t handle, uint32_t timeout_ms) { + serial_dev_prv_t* p_this = darray_find(s_darray, handle); + return_value_if_fail(p_this, RET_FAIL); + if (ring_buffer_size(p_this->rb)) { + return RET_OK; + } + sleep_ms(timeout_ms); + return RET_TIMEOUT; +} + +int32_t serial_read(serial_handle_t handle, uint8_t* buff, uint32_t max_size) { + int fd = serial_handle_get_fd(handle); + serial_dev_prv_t* p_this = darray_find(s_darray, handle); + return_value_if_fail(fd >= 0, RET_FAIL); + return ring_buffer_read(p_this->rb, buff, max_size); +} + +int32_t serial_write(serial_handle_t handle, const uint8_t* buff, uint32_t max_size) { + int fd = serial_handle_get_fd(handle); + return_value_if_fail(fd >= 0, RET_FAIL); + int32_t cnt = aw_write(fd, buff, max_size); + return_value_if_fail(cnt >= 0, cnt); + return cnt; +} + +int serial_close(serial_handle_t handle) { + int fd = serial_handle_get_fd(handle); + serial_dev_prv_t* p_this = darray_find(s_darray, handle); + return_value_if_fail(aw_close(fd) == 0, RET_FAIL); + darray_remove(s_darray, handle); + return RET_OK; +} + +ret_t serial_config(serial_handle_t handle, uint32_t baudrate, bytesize_t bytesize, + stopbits_t stopbits, flowcontrol_t flowcontrol, parity_t parity) { + struct aw_serial_dcb dcb; + struct aw_serial_timeout timeout; + ret_t ret; + serial_dev_prv_t* p_this = darray_find(s_darray, handle); + + int fd = serial_handle_get_fd(handle); + return_value_if_fail(flowcontrol != flowcontrol_software, RET_FAIL); + return_value_if_fail(fd >= 0 && p_this, RET_FAIL); + + if (!p_this->is_usb2uart) { + ret = aw_serial_dcb_get(fd, &dcb); + return_value_if_fail(ret == RET_OK, RET_FAIL); + + dcb.baud_rate = baudrate; + dcb.byte_size = bytesize; + dcb.stop_bits = stopbits; + + if (flowcontrol == flowcontrol_hardware) { + dcb.f_rtsctrl = 1; + dcb.f_ctsflow = 1; + } + if (parity == 1) { + dcb.parity = 1; + } + + ret = aw_serial_dcb_set(fd, &dcb); + return_value_if_fail(ret == RET_OK, RET_FAIL); + + /* 串口超时配置获取 */ + ret = aw_serial_timeout_get(fd, &timeout); + return_value_if_fail(ret == RET_OK, RET_FAIL); + + timeout.rd_timeout = 1000; /* 读总超时 1s */ + timeout.rd_interval_timeout = 50; /* 码间超时为 50ms */ + + /* 配置串口超时 */ + ret = aw_serial_timeout_set(fd, &timeout); + return_value_if_fail(ret == RET_OK, RET_FAIL); + } + + if (!p_this->thread) { + p_this->thread = tk_thread_create(thread_serial_recv, p_this); + // tk_thread_set_priority(p_this->thread, 6); + tk_thread_set_stack_size(p_this->thread, 2048); + ENSURE(tk_thread_start(p_this->thread) == RET_OK); + } + + return RET_OK; +} +#endif /* __AWORKS_LP__ */ + +#ifdef __AWORKS__ + +#include "aworks.h" +#include "io/aw_stropts.h" +#include "io/aw_fcntl.h" +#include "io/aw_unistd.h" + +#include "aw_serial.h" + +int serial_handle_get_fd(serial_handle_t handle) { + return handle->dev; +} + +serial_dev_t serial_handle_get_dev(serial_handle_t handle) { + return handle->dev; +} + +serial_handle_t serial_open(const char* port) { + serial_handle_t handle = TKMEM_ZALLOC(serial_info_t); + return_value_if_fail(handle != NULL && port != NULL && *port != '\0', NULL); + handle->dev = aw_open(port, 0, O_RDWR); + + return handle; +} + +ret_t serial_iflush(serial_handle_t handle) { + int fd = serial_handle_get_fd(handle); + return aw_ioctl(fd, AW_FIORFLUSH, NULL) == 0 ? RET_OK : RET_FAIL; +} + +ret_t serial_oflush(serial_handle_t handle) { + int fd = serial_handle_get_fd(handle); + return aw_ioctl(fd, AW_FIOWFLUSH, NULL) == 0 ? RET_OK : RET_FAIL; +} + +ret_t serial_wait_for_data(serial_handle_t handle, uint32_t timeout_ms) { + int len = 0; + int fd = serial_handle_get_fd(handle); + while (timeout_ms) { + aw_ioctl(fd, AW_FIONREAD, &len); + if (len > 0) { + return RET_OK; + } + sleep_ms(10); + timeout_ms -= tk_min(timeout_ms, 10); + } + return RET_TIMEOUT; +} + +int32_t serial_read(serial_handle_t handle, uint8_t* buff, uint32_t max_size) { + int fd = serial_handle_get_fd(handle); + return aw_read(fd, buff, max_size); +} + +int32_t serial_write(serial_handle_t handle, const uint8_t* buff, uint32_t max_size) { + int fd = serial_handle_get_fd(handle); + return aw_write(fd, buff, max_size); +} + +int serial_close(serial_handle_t handle) { + int fd = serial_handle_get_fd(handle); + return aw_close(fd); +} + +ret_t serial_config(serial_handle_t handle, uint32_t baudrate, bytesize_t bytesize, + stopbits_t stopbits, flowcontrol_t flowcontrol, parity_t parity) { + struct aw_serial_dcb dcb; + int fd = serial_handle_get_fd(handle); + return_value_if_fail(flowcontrol != flowcontrol_software, RET_FAIL); + + memset(&dcb, 0, sizeof(dcb)); + dcb.baud_rate = baudrate; + dcb.byte_size = bytesize; + dcb.stop_bits = stopbits; + + if (flowcontrol == flowcontrol_hardware) { + dcb.f_rtsctrl = 1; + dcb.f_ctsflow = 1; + } + if (parity == 1) { + dcb.parity = 1; + } + + if (0) { + struct aw_serial_timeout tm = {.rd_interval_timeout = 10, .rd_timeout = 100}; + aw_ioctl(fd, AW_TIOCRDTIMEOUT, &tm); + } + return aw_ioctl(fd, AW_TIOSETOPTIONS, &dcb); +} + +#endif /* __AWORKS__ */ diff --git a/src/platforms/aworkslp/socket.c b/src/platforms/aworkslp/socket.c new file mode 100644 index 000000000..412b07094 --- /dev/null +++ b/src/platforms/aworkslp/socket.c @@ -0,0 +1,31 @@ +/** + * File: socket_helper.h + * Author: AWTK Develop Team + * Brief: socket helper functions + * + * Copyright (c) 2019 - 2021 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "tkc/mem.h" +#include "tkc/socket_helper.h" + +#ifdef WITH_SOCKET + +int socketpair(int family, int type, int flags, int fd) { + return -1; +} + +#endif /*WITH_SOCKET*/ diff --git a/src/platforms/aworkslp/thread.c b/src/platforms/aworkslp/thread.c new file mode 100644 index 000000000..bc6c62d4c --- /dev/null +++ b/src/platforms/aworkslp/thread.c @@ -0,0 +1,149 @@ +/** + * File: mutex.c + * Author: AWTK Develop Team + * Brief: mutex + * + * Copyright (c) 2018 - 2018 Guangzhou ZHIYUAN Electronics Co.,Ltd. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * License file for more details. + * + */ + +/** + * History: + * ================================================================ + * 2021-12-16 Wang LinFu created + * + */ + +#include "aworks.h" +#include "aw_task.h" + +#include "tkc/mem.h" +#include "tkc/thread.h" + +struct _tk_thread_t { + void* args; + tk_thread_entry_t entry; + + aw_task_id_t id; + bool_t running; + + const char* name; + uint32_t stack_size; + uint32_t priority; + void* status; +}; + +tk_thread_t* tk_thread_create(tk_thread_entry_t entry, void* args) { + return_value_if_fail(entry != NULL, NULL); + + tk_thread_t* thread = (tk_thread_t*)TKMEM_ZALLOC(tk_thread_t); + return_value_if_fail(thread != NULL, NULL); + + thread->id = AW_TASK_ID_INVALID; + thread->args = args; + thread->entry = entry; + thread->name = "tk_thread"; + thread->stack_size = 1024; + thread->priority = aw_task_lowest_priority(); + + return thread; +} +ret_t tk_thread_set_name(tk_thread_t* thread, const char* name) { + return_value_if_fail(thread != NULL && name != NULL, RET_BAD_PARAMS); + + thread->name = name; + + return RET_OK; +} +ret_t tk_thread_set_stack_size(tk_thread_t* thread, uint32_t stack_size) { + return_value_if_fail(thread != NULL, RET_BAD_PARAMS); + + thread->stack_size = stack_size; + + return RET_OK; +} + +int32_t tk_thread_get_priority_from_platform(tk_thread_priority_t priority) { + int32_t lowest_priority = aw_task_lowest_priority(); + int32_t priority_count = aw_task_priority_count(); + ENSURE(priority_count >= TK_THREAD_PRIORITY_TIME_CRITICAL); + switch (priority) { + case TK_THREAD_PRIORITY_TIME_CRITICAL: + return lowest_priority - 6; + case TK_THREAD_PRIORITY_HIGHEST: + return lowest_priority - 5; + case TK_THREAD_PRIORITY_ABOVE_NORAML: + return lowest_priority - 4; + case TK_THREAD_PRIORITY_NORMAL: + return lowest_priority - 3; + case TK_THREAD_PRIORITY_BELOW_NORAML: + return lowest_priority - 2; + case TK_THREAD_PRIORITY_LOWEST: + return lowest_priority - 1; + default: + return lowest_priority; + } +} + +ret_t tk_thread_set_priority(tk_thread_t* thread, tk_thread_priority_t priority) { + return_value_if_fail(thread != NULL, RET_BAD_PARAMS); + + thread->priority = tk_thread_get_priority_from_platform(priority); + + return RET_OK; +} +ret_t tk_thread_start(tk_thread_t* thread) { + return_value_if_fail(thread != NULL && !thread->running, RET_BAD_PARAMS); + + thread->id = aw_task_create(thread->name, thread->priority, thread->stack_size, thread->entry, + thread->args); + + if (thread->id == AW_TASK_ID_INVALID) { + return RET_FAIL; + } + + if (aw_task_startup(thread->id) == AW_OK) { + thread->running = TRUE; + } else { + return RET_FAIL; + } + + return RET_OK; +} +ret_t tk_thread_join(tk_thread_t* thread) { + return_value_if_fail(thread != NULL, RET_BAD_PARAMS); + + if (!aw_task_valid(thread->id) || aw_task_join(thread->id, &thread->status) == AW_OK) { + thread->id = AW_TASK_ID_INVALID; + thread->running = FALSE; + return RET_OK; + } else { + return RET_FAIL; + } +} + +void* tk_thread_get_args(tk_thread_t* thread) { + return_value_if_fail(thread != NULL, NULL); + + return thread->args; +} + +ret_t tk_thread_destroy(tk_thread_t* thread) { + return_value_if_fail(thread != NULL && thread->id != AW_TASK_ID_INVALID, RET_BAD_PARAMS); + + return_value_if_fail(aw_task_terminate(thread->id) == AW_OK, RET_FAIL); + + memset(thread, 0x00, sizeof(tk_thread_t)); + TKMEM_FREE(thread); + + return RET_OK; +} + +uint64_t tk_thread_self(void) { + return (uint64_t)aw_task_id_self(); +} diff --git a/tests/fscript_test.cc b/tests/fscript_test.cc index e778e5166..783832e55 100644 --- a/tests/fscript_test.cc +++ b/tests/fscript_test.cc @@ -1360,4 +1360,3 @@ TEST(FExr, global) { TK_OBJECT_UNREF(obj); } -