A40i使用笔记:重定向串口输出信息到telnet端口(任意定向)

一、前言

在嵌入式Linux系统中,我是用的是A40i,有时通过远程(telnet或者ssh)登录到现场设备,想看程序的实时打印的调试信息,需要将输出到串口的调试信息重定向到当前登录的终端界面上。

下面是实现的代码,可以将输出到串口的日志信息,重定向到当前的telnet或者ssh界面.

二、环境

Ubuntu16.0

window10

A40i

参考连接:

linux下tty, ttyn, pts, pty, ttySn, console理解

linux C语言编译后执行文件从命令输入参数

如何将串口输出的调试信息重定向到telnet/ssh界面上

三、正文

方式一:使用单独程序控制输出信息定向

代码量不多,直接上代码,将代码打包成console_redirect.c

/*
    内核的打印不能重定向过来,应用层打印可以重定向打印过来,
因为通过telnet到我的A40i上面的可执行qt程序,
系统启动过程中我的程序还未启动,telnet是连接不上的,
直到我的telnet连接上之后,
才可以将默认串口ttys0的打印信息重定向到我的程序对应外部网口上(服务器模式),
根据自己需求重定向的目标位置,可参考参考连接中的帖子    
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int tty = -1;
    char *tty_name = NULL;

    if(argc < 2){//判断是否传入参数,只输入./xx是一个参数,至少需要第二个参数判断
        printf("miss argument\n");
        return 0;
    }

    /* 获取当前tty名称 */
    tty_name = ttyname(STDOUT_FILENO);
    printf("tty_name: %s\n", tty_name);

    if(!strcmp(argv[1], "on")){//判断第二个参数是否为on
        /* 重定向console到当前tty */
        tty = open(tty_name, O_RDONLY | O_WRONLY);
        ioctl(tty, TIOCCONS);
        perror("ioctl TIOCCONS");
    }
    else if(!strcmp(argv[1], "off")){//判断第二个参数是否为off
        /* 恢复console */
        tty = open("/dev/console", O_RDONLY | O_WRONLY);
        ioctl(tty, TIOCCONS);
        perror("ioctl TIOCCONS");
    }
    else{//判断第二个参数不是需要的,认为无效
        printf("error argument\n");
        return 0;
    }

    close(tty);
    return 0;
}

程序很简单,就是首先判断参数是否有输入,当没有输入任何参数或者参数不是指定时,返回未设置数据。当验证成功之后就会上设置你想要的,可以设置以下几个定向位置tty, ttyn, pts, pty, ttySn, console。具体含义参照如下

  • /dev/tty

控制终端,即当前用户正在使用的终端,是一个映射,指向当前所使用的终端(例如/dev/tty1,/dev/pts/0)。往/dev/tty下写数据总是写到当前终端。

  • /dev/ttyn

虚拟终端,例如ubuntu不启动图形界面时,那么就会默认连接到/dev/tty1这个虚拟终端。

  • /dev/pts/n

伪终端,例如网络登录的telnet就是使用伪终端。这是UNIX98的实现风格,slave为/dev/pts/n是,master一般为/dev/ptmx。

  • /dev/pty[p-za-e][0-9a-f]

伪终端,这是BSD的实现风格,slave一般使用/dev/tty[p-za-e][0-9a-f]这种格式,而master一般使用/dev/pty[p-za-e][0-9a-f]这种格式。

  • /dev/ttySn

串行终端,串口设备对应的终端。

  • /dev/console

应用层的控制台,一些进程的打印信息会输出到控制台。在用户层和内核都有一个console,分别对应printf和printk的输出。kernel下的console是输入输出设备driver中实现的简单的输出console,只实现write函数,并且是直接输出到设备。user空间下的console,实际就是tty的一个特殊实现,大多数操作函数都继承tty,所以对于console的读写,都是由kernel的tty层来最终发送到设备。

往/dev下各个终端设备写数据测试:
往/dev/ttyn, /dev/pts/n, /dev/ptyn, /dev/ttySn会写到对应的终端上去。
往/dev/tty上写则会写到当前终端。
往/dev/console写情况则不太一样,在ubuntu上测试时(没启动图像界面,启动的/dev/tty1)会写到/dev/tty1。板子上则会写到/dev/ttyS0。
往A40i中写入时,连接外部telnet后,会识别出/dev/pts/0已连接,所以A40i重定向目标就是/dev/pts/0

下面就介绍一下具体的操作步骤

1.首先打开Ubuntu进入到终端,cd命令到console_redirect.c文件路径,console_redirect.c文件已经有源码在上面,内容看文章根据自己需求适当改变一点。

2.执行编译命令gcc -o 生成文件名称 被编译c文件名称,我的执行如下

 gcc -o testprint console_redirect.c

生成一个testprint 可执行程序

3.可以直接将程序导入到板子中目标路径进行操作,也可以在Ubuntu下验证一下功能是否好用,在文件路径下执行命令./testprint on,即进入程序中的判断on条件中,执行./testprint off进入off条件中,

 

 4.查看想要输出信息的终端是否有信息输出

5.烧录程序到板子中提示不能执行,是因为没有进行交叉编译的原因,将这个c文件用对应开发板的交叉编译器进行编译出对应的可执行文件,即可再通过命令运行起来,然后设置定向问题。

优点:单独功能可控

缺点:稍微麻烦一些,还得单独配置一个文件

方式二:使用telnet强制切换程序运行

这个方式比较暴力,正常程序启动实在内部自动启动的,这时候启动完毕,人家默认的打印信息是内部串口,而不是外部的telnet网络终端。然后我的实现方式是使用外部telnet终端强制将程序关闭,然后从telnet终端重新打开一遍程序,这样程序默认的输出端就是telnet终端了,实现图如下

先执行杀掉程序   killall demo_net

然后在打开程序  ./demo_net

可以看到程序打印信息从网口终端打印出来

串口终端是login[1296]: root login on 'pts/0'

网口终端是tty_name: /dev/pts/0

 优点:简单操作

缺点:在telnet网络终端不能向串口终端那样同时发送命令和接收打印信息(因为是打开一个程序,不能在输入命令,只有把程序退出才可再次执行命令),但对于调试查看打印信息足够

方式三:程序内部编译进相关控制程序

调用以下编码,目前实现的只是单路telnet,并没有实现完全的任意定向,嘿嘿

//重定向 on到当前输出端,off默认输出端
void redirect(QString res)
{
    //重定向打印信息
    int tty = -1;
    char *tty_name = NULL;
    tty_name = ttyname(STDOUT_FILENO);//获取当前tty名称
    printf("tty_name: %s\n", tty_name);

    if(res=="on"){//判断第二个参数是否为on
        /* 重定向console到当前tty */
        tty = open("/dev/pts/0", O_RDONLY | O_WRONLY);//tty_name
        ::ioctl(tty, TIOCCONS);
        ::perror("ioctl TIOCCONS");
    }
    else if(res=="off"){//判断第二个参数是否为off
        /* 恢复console */
        tty = open("/dev/console", O_RDONLY | O_WRONLY);
        ::ioctl(tty, TIOCCONS);
        ::perror("ioctl TIOCCONS");
    }
    ::close(tty);
}

执行代码如下

///重定向测试
    else if(dataTemp.mid(0,6).toUpper()=="5AA525"&&dataTemp.mid(8,8).toUpper()=="53544F50"){
        uchar num=dataTemp.mid(6,2).toInt(&ok,16);
        qDebug()<<"receive redirect test value is "<<QString::number(num);
        if(num){//重定向到外部telnet
            redirect("on");
        }
        else{//重定向到内部串口
            redirect("off");
        }
    }

效果:

 

优点:可以控制输出端,输出端同时也可以进行命令下发,比方式二不那么暴力

缺点:每次需要单独配置一下输出位置,目前只有一个telnet端,无法进行第二和telnet端输出,当网线断开后重新连接,系统检测不到第一个telnet端断开,还是向一个看不见的telnet端输出信息,所以尽量保持在系统启动后,网线连接是可靠的。 

方式四:优化方式三实现任意输出

目前比较忙碌,没有时间也暂时没有完全必要使用这个功能,后续需求使用在研究实现方式。

四、结语

年少轻狂的岁月  沉淀下来的是那些再也回不到的过去

而总让人感叹的  则是未曾珍惜而失去的那些

最宽阔的是海洋  比海洋更宽阔的是天空  比天空更宽阔的是人的胸怀

当你紧握着手 里面什么都没有  当你打开双手 世界就在你手中

简单说明 工具支持:串口通讯、串口代理、TCP、UDP、Telnet、Ping、TFtp等通讯测试 1、本工具支持固定预定义命令,命令可以进行分组,由树形控件管理。点击“命令编辑”即可编辑预定义命令, 编辑保存后点击“命令更新”按钮,新命令即显示在左侧“命令树”中,预定义命令支持ASCII码字符串格式 、十六进制格式与转义(混合)命令格式(如"abc\r\n12345\xAB \x45"); 2、支持动态命令,如命令中含有帧长度、校验等数据项目,命令可以进行分组,由树形控件管理。方法上采用 Lua脚本语言进行扩展,扩展的界面内容包含终端窗的右键菜单、脚本窗的按钮事件、扩展的树命令; 3、支持命令终端模式,功能类似Windows下的超级终端,可以进行复制、粘贴等操作,可以上下翻页滚动; 在终端窗可以通过鼠标滚轮上下滚动,可以通过“Ctrl+箭头”、“Ctrl+翻页键”上下翻页操作; 4、工具支持ZModem协议进行文件下载、上传,方便与Linux终端间交换数据; 5、支持用Lua脚本对接收到的数据进行解析,支持用脚本语言直接进行发送操作; 6、支持数据触发模式,当串口(Socket)接收到预定义格式的数据时,可以直接触发脚本内指定的函数事件; 7、支持串口回环模式,发出的数据自动返回,便于脚本调试; 8、支持常用工具嵌入到本界面内部,由脚本定制具体程序名称,如计算器、Dnw、记事本、命令行等,在操作上 形同一个整体; 9、具有串口数据记录功能,每天记录一个文件,可以加上时间标记,方便查看历史操作、历史数据; 10、可以采用脚本进行定时发送、循环发送、总线循访等操作流程; 11、Lua脚本支持发送字节到串口(Socket)、发送字符串到串口(Socket)、延时、定时器、事件触发、界面定制等操作; 12、支持命令行内容自动滚动记录功能,方便使用历史命令; 13、支持窗总在最前模式(top on most),方便在进行其它任务,监通讯操作; 14、支持脚本扩展的语音提示功能(播放指定的Wav文件),可以用在接收到指定数据、帧错误、校验错、定时 操作完毕、超时等场合,方便提醒调试人员; 15、支持发送文件操作,包含每次发送的长度、间隔时间等,也可以通过脚本语言读取文件进行自定义格式发送, 如包含同步、长度、校验等信息。 ... ------------lua 可调用的服务函数--------------------------------- SendByte 向串口(Socket)发送一个字节 SendString 向串口(Socket)发送字符串 SendHexString 向串口(Socket)发送字符串,例子:SendHexString("12 34 56 AB 5F"); GetString 通过录入窗获取字符串 Sleep 休眠 Wait 等待,事件继续触发 GetDateTimeStr 取得当前时间字符串 Print 打印输出信息输出 print 打印输出信息输出 PrintToCommWin 打印输出信息串口信息 PrintAsChar 打印输出信息输出(数据类型转换为字符型) ClearOutput 清除输出内容 IntToChar 数据类型转换为字符型 SetButtonText 设置按钮文本 WinExec 运行外部应用程序 WinExecInWindow 运行外部应用程序(嵌入到窗内部) GetExeDir 取得应用程序的路径 SetMenuItemText 设置终端模式下的串口(Socket)信息的弹出菜单内容 GetClipboardText 获取剪贴板数据 CopyToClipboard 复制数据到剪贴板 AddLuaTreeNode 在扩展命令树中增加一个节点 PlayWave 播放语音文件 SetCmdLineText 设置命令输入行内容 GetCmdLineText 获取命令输入行内容 IntToHex 数据转换为十六进制字符串 IntToStr 数据转换为字符串 StrToInt 字符串转换为整形 bit_not 数据取反 bit_and 数据相与 bit_or 数据相或 bit_xor 数据相异或 bit_shl 数据左移 bit_shr 数据右移 GetFileName 获取文件名 inet_addr ip地址转换 SubString 取得子字符串 SetLuaTreeNodeText 设置树节点文字 SetLuaTreeNodeParam 设置树节点参数 ShowVclForm 显示扩展界面 ShowOutputForm 显示输出界面 ShowCodeForm 关闭代码窗 HideCodeForm 关闭代码窗 HideSendForm 关闭发送窗 ShowSendForm 显示发送窗 GetPathName 通过GUID获取设备名称 FileOpen 打开文件 FileSeek 移动文件指针 FileRead 读取文件 FileWrite 写文件 FileClose 关闭文件 AllocMem 分配内存 FillMem 填充1个字节到内容 GetMem 获取1字节内容内容 FreeMem 是否内存 SaveParam 保存参数到UserParam.ini GetParam 读取参数,从UserParam.ini AddBufDat 对内存内容按字节累加求和,通常用于计算校验 Update 界面刷新 ShowMessage 消息窗 ShowLeftTools 显示左边工具栏 ShowRightTools 显示右边工具栏 ShowTerminal 显示终端窗 HideLeftTools 隐藏左边工具栏 HideRightTools 隐藏右边工具栏 HideTerminal 隐藏终端窗 ClearCommWin 清除通讯窗内容 GotoCommWin 设置坐标 PrintToTerminal 打印信息到终端窗 GetSendWinSelText 取得发送窗中选中的数据 ClearVclControls 清除脚本语言创建的控件 ------------lua 事件----------------------------------- ReceivedByte 串口(Socket)接收到一个字节数据 ReceivedTrigData 串口(Socket)接收到特定格式数据 ProcessTrigData 串口(Socket)接收完特定格式数据后进行一次性处理 Timer100ms 100毫秒定时器事件 Timer500ms 1500毫秒定时器事件 Timer1000ms 1000毫秒定时器事件 Button1Clicked 按钮1单击事件 Button2Clicked 按钮2单击事件 Button3Clicked 按钮3单击事件 Button4Clicked 按钮4单击事件 Button5Clicked 按钮5单击事件 Button6Clicked 按钮6单击事件 Button7Clicked 按钮7单击事件 Button8Clicked 按钮8单击事件 MenuItem0Clicked 弹出菜单项0单击事件 MenuItem1Clicked 弹出菜单项1单击事件 MenuItem2Clicked 弹出菜单项2单击事件 MenuItem3Clicked 弹出菜单项3单击事件 MenuItem4Clicked 弹出菜单项4单击事件 MenuItem5Clicked 弹出菜单项5单击事件 MenuItem6Clicked 弹出菜单项6单击事件 MenuItem7Clicked 弹出菜单项7单击事件 MenuItem8Clicked 弹出菜单项8单击事件 MenuItem9Clicked 弹出菜单项9单击事件 MenuItem10Clicked 弹出菜单项10单击事件 MenuItem11Clicked 弹出菜单项11单击事件 MenuItem12Clicked 弹出菜单项12单击事件 MenuItem13Clicked 弹出菜单项13单击事件 MenuItem14Clicked 弹出菜单项14单击事件 MenuItem15Clicked 弹出菜单项15单击事件 MenuItem16Clicked 弹出菜单项16单击事件 MenuItem17Clicked 弹出菜单项17单击事件 MenuItem18Clicked 弹出菜单项18单击事件 MenuItem19Clicked 弹出菜单项18单击事件 转义字符 含义 ASCII码(16/10进制) \n 换行符(LF) 0AH/10 \r 回车符(CR) 0DH/13 \\ 反斜杠 5CH/92 \ddd 任意字符 1~3位十进制 \xhh 任意字符 1~2位十六进制 继续完善中,欢迎提出宝贵意见。 本软件版本:V1.25 作者:baohongjie@126.com
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大桶矿泉水

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值