注:若用户未使能 stdio function 时,调用printf函数时,将不会有任何输出。
与UART设备不同,USB设备为动态设备,因此重定向printf函数时,需要注意以下几个关键步骤:
由于AWorksLP中利用posix file相关操作接口对printf函数进行适配,故在重映射端口时,需将 support libc file operations 使能,并取消默认选择UART设备作为printf函数的适配,具体如下图所示。
USB设备为动态设备,因此需要持续检测设备的是否存在情况。可通过初始化一个动态设备检测任务,对设备的是否存在情况进行周期性检测。
while true:
access (device)
delay()
在检测到USB设备存在时,仅需将设备与标准文件流(stdio中的stdin、stdout、stderr,且在C库中被假定为交互设备,并约定了这些设备的文件描述符依次为0、1、2)关联起来。故在使用时,我们仅需将描述符0、1、2与USB串口设备即可,其伪代码如下所示。
while true:
if access (device):
0 = open (device)
duplicate 1 to 0
duplicate 2 to 0
delay()
1.4 清理文件描述符
while true:
if access (device):
0 = open (device)
duplicate 1 to 0
duplicate 2 to 0
else:
close (device)
delay()
3. 简单示例
static int __dynamic_stdin_fd = -1;
static aw_err_t __dynamic_stdout_ret = -AW_EBADF;
static aw_err_t __dynamic_stderr_ret = -AW_EBADF;
aw_err_t aw_printf_redirect_dynamic_dev(void)
{
int find = -AW_ENODEV;
// 检测动态设备
find = aw_access(AW_DYNAMIC_DEV_PATH, AW_F_OK);
if(find == AW_OK) {
// 关联标准文件流
if(__dynamic_stdin_fd < 0)
{
__dynamic_stdin_fd = \
aw_open_at(AW_DYNAMIC_DEV_PATH,AW_O_RDWR,0,0);
__dynamic_stdout_ret = aw_dup2(0, 1);
__dynamic_stderr_ret = aw_dup2(0, 2);
return AW_OK;
}
}
else {
// 清理文件描述符
if(__dynamic_stdin_fd >= 0) {
aw_close(0);
__dynamic_stdin_fd = -1;
}
if (__dynamic_stdout_ret == AW_OK) {
aw_close(1);
__dynamic_stdout_ret = -AW_EBADF;
}
if (__dynamic_stderr_ret == AW_OK) {
aw_close(2);
__dynamic_stderr_ret = -AW_EBADF;
}
}
return -AW_ENODEV;
}
int aw_main(void)
{
int ret;
aw_kprintf("hello world\n");
printf("hello world\n");
while(1) {
ret = aw_printf_redirect_dynamic_dev();
if (AW_OK == ret)
break;
// 设置检测周期
AW_TASK_DELAY(100);
}
aw_kprintf("hello world, ZLG\n");
printf("hello world, ZLG\n");
return 0;
}
本文所演示平台使用的是GCC编译器,其对应C库为NEWLIB标准库。在AWorksLP中printf函数的底层输出接口在AWorksLP中实现为_write_r 函数,其具体代码实现如下所示。
__attribute__((__used__)) _ssize_t
_write_r(struct _reent *ptr, int fd, const void *buf, size_t nbytes)
{
return aw_write(fd,buf,nbytes);
}
需要值得注意的是,上述适配方式仅兼容NEWLIB,若是其他编译器,其实现以及接口不尽相同,下表仅给出部分以供参考,在使用时需根据实际情况进行调整。
工具链 | 标准库 | 底层接口 |
GCC | NEWLIB | _write_r |
ARMCC | ARMCLIB | _sys_write |
ARMCLANG | ARMCLIB | _sys_write |
更多往期文章,请点击“ 阅读原文 ”。