printf函數(shù)作為標準庫定義的格式化輸出方式,本文將介紹其在AWorksLP下默認適配以及重映射至熱拔插設備端口的實現(xiàn)。
默認適配
AWorksLP中默認已經(jīng)對printf函數(shù)完成相關適配工作,且默認被適配在UART設備。用戶可以在圖形化配置界面中使能 support the stdio functions ,并選擇期望UART設備進行輸出,具體配置如下圖所示。
注:若用戶未使能 stdio function 時,調(diào)用printf函數(shù)時,將不會有任何輸出。
本文將使用 EPC6450-AWI 平臺,選擇標有絲印為DUART的調(diào)試串口(UART0設備)進行printf功能演示測試。將TTL轉(zhuǎn)USB串口模塊的TXD與板子的RXD絲印連接,RXD與板子的TXD絲印,將另一端的USB口接入電腦。
啟動串口調(diào)試助手,搜索并打開串口模塊的設備端口號后,在工程中調(diào)用printf函數(shù),根據(jù)下圖可知,printf函數(shù)適配UART0設備成功。
重定向至其他設備
嵌入式的諸多應用在UART設備資源受限的情況下,可能存在將printf函數(shù)重定向到其他設備需求。為此,筆者將以EPC6450-AWI平臺的USB串口設備為例進行說明。
1.?實施步驟
與UART設備不同,USB設備為動態(tài)設備,因此重定向printf函數(shù)時,需要注意以下幾個關鍵步驟:
1.1 支持NEWLIB標準庫函數(shù)
由于AWorksLP中利用posix file相關操作接口對printf函數(shù)進行適配,故在重映射端口時,需將 support libc file operations 使能,并取消默認選擇UART設備作為printf函數(shù)的適配,具體如下圖所示。
1.2 檢測動態(tài)設備
USB設備為動態(tài)設備,因此需要持續(xù)檢測設備的是否存在情況??赏ㄟ^初始化一個動態(tài)設備檢測任務,對設備的是否存在情況進行周期性檢測。
while true:
? ?access (device)
? ?delay()
1.3 關聯(lián)標準文件流
在檢測到USB設備存在時,僅需將設備與標準文件流(stdio中的stdin、stdout、stderr,且在C庫中被假定為交互設備,并約定了這些設備的文件描述符依次為0、1、2)關聯(lián)起來。故在使用時,我們僅需將描述符0、1、2與USB串口設備即可,其偽代碼如下所示。
while true:
if access (device):
0 = open (device)
duplicate 1 to 0
duplicate 2 to 0
delay()
1.4 清理文件描述符
檢測到USB設備不存在時,需及時取消設備與標準文件流的關聯(lián)。即根據(jù)設備的打開情況,對文件描述符進行清理,以便之后重新關聯(lián)標準文件流。
while true:
? ?if access (device):
? ? ? ?0 = open (device)
? ? ? ?duplicate 1 to 0
? ? ? ?duplicate 2 to 0
? ?else:
? ? ? ?close (device)
? ?delay()
2. 基礎配置
在EPC6450-AWI平臺標有絲印為Type-C的接口處,插上Type-C線,將Type-C線的另一端USB口連接電腦。并在圖形化配置界面,將USB設備選擇為CDC串口設備。
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;
? ?// 檢測動態(tài)設備
? ?find = aw_access(AW_DYNAMIC_DEV_PATH, AW_F_OK);
? ?if(find == AW_OK) {
? ? ? ?// 關聯(lián)標準文件流
? ? ? ?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 worldn");
? ?printf("hello worldn");
? ?while(1) {
? ? ? ?ret = aw_printf_redirect_dynamic_dev();
? ? ? ?if (AW_OK == ret)
? ? ? ? ? ?break;
? ? ? ?// 設置檢測周期
? ? ? ?AW_TASK_DELAY(100);
? ?}
? ?aw_kprintf("hello world, ZLGn");
? ?printf("hello world, ZLGn");
? ?return 0;
}
啟動串口調(diào)試助手,搜索并打開DEBUG UART設備與CDC串口設備的端口號后,運行上文示例程序。根據(jù)下圖可知,USB設備枚舉后,printf函數(shù)成功重定向到了CDC串口設備。
總結
實現(xiàn)重定向printf函數(shù)時主要關注以下兩個關鍵點:重寫NEWLIB標準庫中printf函數(shù)的底層實現(xiàn);將指定設備以標準文件流約定的文件描述符打開。