本文主要是介绍友善之臂comtest.c串口编译程序详解 希望对大家有帮助,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
友善comtest.c串口编译程序详解 希望对大家有帮助
说明 :armcomtest 是友善之臂为了方便测试而开发的linux 下的简易实用串口终端程
序,它使用标准的系统调用,和硬件无关。一般Linux 系统系统启动后,串口 0,1,2对应的设
备名分别为 /dev/ttySAC0,1,2,3
测试串口2 需要借助另一台带有串口的PC ,连接好 COM2 和另一台PC的串口,并设置该PC的超级终端为波特率115200 ,
无流控制,其他默认。
在命令行下输入:
# armcomtest –d /dev/ttySAC1 - o
这时如果输入字符会在另一台PC的超级终端出现,反之亦然。
如果要测试串口3,则需要连接扩展小板的COM3 ,并在命令行输入:
# armcomtest –d /dev/ttySAC2 - o
# include <stdio.h>
# include <stdlib.h>
# include <termio.h>
# include <unistd.h>
# include <fcntl.h>
# include <getopt.h>
# include <time.h>
# include <errno.h>
# include <string.h>
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(1);
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
static int SerialSpeed(const char *SpeedString) //波特率选择
{
int SpeedNumber = atoi(SpeedString);
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200);
TestSpeed(2400);
TestSpeed(4800);
TestSpeed(9600);
TestSpeed(19200);
TestSpeed(38400);
TestSpeed(57600);
TestSpeed(115200);
TestSpeed(230400);
Error("Bad speed");
return -1;
}
static void PrintUsage(void) //打印消息
{
fprintf(stderr, "comtest - interactive program of comm port\n");
fprintf(stderr, "press [ESC] 3 times to quit\n\n");
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");
fprintf(stderr, " -7 7 bit\n");
fprintf(stderr, " -x hex mode\n");
fprintf(stderr, " -o output to stdout too\n");
fprintf(stderr, " -c stdout output use color\n");
fprintf(stderr, " -h print this help\n");
exit(-1);
}
static inline void WaitFdWriteable(int Fd)
/*
类似于一种宏定义
这种宏定义在形式上类似于一个函数,
但在使用它时,仅仅只是做预处理器符号表中的简单替换,
因此它不能进行参数有效性的检测,
也就不能享受C++编译器严格类型检查的好处,
另外它的返回值也不能被强制转换为可转换的合适的类型,
这样,它的使用就存在着一系列的隐患和局限性。
*/
{
fd_set WriteSetFD;
FD_ZERO(&WriteSetFD);
FD_SET(Fd, &WriteSetFD);
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {
Error(strerror(errno));
} //select用来监控
}
int main(int argc, char **argv)
{
int CommFd, TtyFd;
struct termios TtyAttr;
struct termios BackupTtyAttr;
int DeviceSpeed = B115200;
int TtySpeed = B115200;
int ByteBits = CS8;
const char *DeviceName = "/dev/ttyS0";
const char *TtyName = "/dev/tty";
int OutputHex = 0;
int OutputToStdout = 0;
int UseColor = 0;
opterr = 0;
for (;;) {
int c = getopt(argc, argv, "d:s:t:7xoch");
/*
函数说明 getopt()用来分析命令行参数。
参数argc和argv是由main()传递的参数个数和内容。
参数optstring 则代表欲处理的选项字符串。
此函数会返回在argv 中下一个的选项字母,
此字母会对应参数optstring 中的字母。
如果选项字符串里的字母后接着冒号“:”,
则表示还有相关的参数,全域变量optarg
即会指向此额外参数。如果getopt()
找不到符合的参数则会印出错信息,
并将全域变量optopt设为“?”字符,
如果不希望getopt()印出错信息,
则只要将全域变量opterr设为0即可。
*/
if (c == -1)
break;
switch(c) {
case 'd':
DeviceName = optarg;
break;
case 't':
TtyName = optarg;
break;
case 's':
if (optarg[0] == 'd') {
DeviceSpeed = SerialSpeed(optarg + 1);
} else if (optarg[0] == 't') {
TtySpeed = SerialSpeed(optarg + 1);
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg);
break;
case 'o':
OutputToStdout = 1;
break;
case '7':
ByteBits = CS7;
break;
case 'x':
OutputHex = 1;
break;
case 'c':
UseColor = 1;
break;
case '?':
case 'h':
default:
PrintUsage();
}
}
if (optind != argc)
PrintUsage();//打印消息
CommFd = open(DeviceName, O_RDWR, 0);
if (CommFd < 0)
Error("Unable to open device");
if (fcntl(CommFd, F_SETFL, O_NONBLOCK) < 0)
Error("Unable set to NONBLOCK mode");
/*
F_SETFL 设置文件描述词状态旗标,
参数arg为新旗标,但只允许O_APPEND、
O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O
*/
memset(&TtyAttr, 0, sizeof(struct termios));
/*
函数原型 void *memset(void *s, int ch, unsigned n);
将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,
块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作,
其返回值为指向S的指针。
将TtyAttr 所指向的内存区域的值全部设置为0 的Ascii值
*/
//设置串口的一些参数
TtyAttr.c_iflag = IGNPAR; //IGNPAR 忽略奇偶校验错误
//c_iflag:输入模式标志,控制终端输入方式,具体参数如表6.3所示。
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;
//CREAD 使用接收器 HUPCL 关闭设备时挂起 CLOCAL 忽略调制解调器线路状态
//c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表6.5所示。
TtyAttr.c_cc[VMIN] = 1; //VMIN 非规范模式读取时的最小字符数
//c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,
//如输入结束符等。c_cc中定义了如表6.7所示的控制字符。
if (tcsetattr(CommFd, TCSANOW, &TtyAttr) < 0)
Warning("Unable to set comm port");
/*
为了使程序控制终端参数,
在标准库中POSIX需要几个函数,
最重要的两个函数为tcsetattr和tcgetattr。
tcgetattr取回一个如图3-34中显示的数据结构的一份拷贝,
该结构为termios,它包含用来改变特殊字符、
设置模式和修改终端其他特性的所有信息。
程序可以检查当前的设置,
当需要时对这些设置进行修改,
然后调用tcsetattr把这个结构写回终端任务中。
头文件
<termios.h>
<unistd.h>
函数形式
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
*/
TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0); //ndelay 自我解释应该是延时的意思
if (TtyFd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;
if (tcgetattr(TtyFd, &BackupTtyAttr) < 0)
Error("Unable to get tty");
//BackupTtyAttr 用于存储获得的终端参数信息
if (tcsetattr(TtyFd, TCSANOW, &TtyAttr) < 0)
//使用tcsetattr函数将修改后的终端参数设置到标准输入中
Error("Unable to set tty");
for (;;) {
unsigned char Char = 0;
fd_set ReadSetFD;
void OutputStdChar(FILE *File)
{
char Buffer[10];
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", Char);
fwrite(Buffer, 1, Len, File);
}
/*
int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);
参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,
可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,
需要监视的描述符没有事件发生则函数返回,返回值为0。
fd_set(它比较重要所以先介绍一下)是一组文件描述字(fd)的集合,
它用一位来表示一个fd(下面会仔细介绍),对于fd_set类型通过下面四个宏来操作:
FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,
在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,
由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
过去,一个fd_set通常只能包含<32的fd(文件描述字),
因为fd_set其实只用了一个32位矢量来表示fd;现在,
UNIX系统通常会在头文件<sys/select.h>中定义常量FD_SETSIZE,
它是数据类型fd_set的描述字数量,其值通常是1024,这样就能表示<1024的fd。
根据fd_set的位矢量实现,我们可以重新理解操作fd_set的四个宏:
fd_set set;
FD_ZERO(&set);
FD_SET(0, &set);
FD_CLR(4, &set);
FD_ISSET(5, &set);
*/
FD_ZERO(&ReadSetFD);
FD_SET(CommFd, &ReadSetFD);
FD_SET( TtyFd, &ReadSetFD);
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {
Error(strerror(errno));
//检测可读的文件的文件描述符的集合
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {
/*
int FD_ISSET(int fd,fd_set *fdset)
宏说明:在调用select()函数后,用FD_ISSET来检测fdset中文件fd有无发生变化
*/
while (read(CommFd, &Char, 1) == 1) {
WaitFdWriteable(TtyFd);
//监控TtyFd这个文件描述符中是否有数据发生变化
//这个函数在上面有定义
// ssize_t write (int fd,const void * buf,size_t count);
//write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。
//当然,文件读写位置也会随之移动。
if (write(TtyFd, &Char, 1) < 0) {
Error(strerror(errno));
}
//如果用到了-O的属性 OutputTostdout 就会变成1就会输出下面的信息
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;34m", 1, 8, stdout);
OutputStdChar(stdout);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout);
fflush(stdout);
}
}
}
if (FD_ISSET(TtyFd, &ReadSetFD)) {
while (read(TtyFd, &Char, 1) == 1) {
static int EscKeyCount = 0;
WaitFdWriteable(CommFd);
if (write(CommFd, &Char, 1) < 0) {
Error(strerror(errno));
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;31m", 1, 8, stderr);
OutputStdChar(stderr);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stderr);
fflush(stderr);
}
if (Char == '\x1b') {
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
// 跳出到退出label
} else
EscKeyCount = 0;
}
}
}
ExitLabel:
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)
Error("Unable to set tty");
return 0;
序,它使用标准的系统调用,和硬件无关。一般Linux 系统系统启动后,串口 0,1,2对应的设
备名分别为 /dev/ttySAC0,1,2,3
测试串口2 需要借助另一台带有串口的PC ,连接好 COM2 和另一台PC的串口,并设置该PC的超级终端为波特率115200 ,
无流控制,其他默认。
在命令行下输入:
# armcomtest –d /dev/ttySAC1 - o
这时如果输入字符会在另一台PC的超级终端出现,反之亦然。
如果要测试串口3,则需要连接扩展小板的COM3 ,并在命令行输入:
# armcomtest –d /dev/ttySAC2 - o
# include <stdio.h>
# include <stdlib.h>
# include <termio.h>
# include <unistd.h>
# include <fcntl.h>
# include <getopt.h>
# include <time.h>
# include <errno.h>
# include <string.h>
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(1);
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
static int SerialSpeed(const char *SpeedString) //波特率选择
{
int SpeedNumber = atoi(SpeedString);
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200);
TestSpeed(2400);
TestSpeed(4800);
TestSpeed(9600);
TestSpeed(19200);
TestSpeed(38400);
TestSpeed(57600);
TestSpeed(115200);
TestSpeed(230400);
Error("Bad speed");
return -1;
}
static void PrintUsage(void) //打印消息
{
fprintf(stderr, "comtest - interactive program of comm port\n");
fprintf(stderr, "press [ESC] 3 times to quit\n\n");
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");
fprintf(stderr, " -7 7 bit\n");
fprintf(stderr, " -x hex mode\n");
fprintf(stderr, " -o output to stdout too\n");
fprintf(stderr, " -c stdout output use color\n");
fprintf(stderr, " -h print this help\n");
exit(-1);
}
static inline void WaitFdWriteable(int Fd)
/*
类似于一种宏定义
这种宏定义在形式上类似于一个函数,
但在使用它时,仅仅只是做预处理器符号表中的简单替换,
因此它不能进行参数有效性的检测,
也就不能享受C++编译器严格类型检查的好处,
另外它的返回值也不能被强制转换为可转换的合适的类型,
这样,它的使用就存在着一系列的隐患和局限性。
*/
{
fd_set WriteSetFD;
FD_ZERO(&WriteSetFD);
FD_SET(Fd, &WriteSetFD);
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {
Error(strerror(errno));
} //select用来监控
}
int main(int argc, char **argv)
{
int CommFd, TtyFd;
struct termios TtyAttr;
struct termios BackupTtyAttr;
int DeviceSpeed = B115200;
int TtySpeed = B115200;
int ByteBits = CS8;
const char *DeviceName = "/dev/ttyS0";
const char *TtyName = "/dev/tty";
int OutputHex = 0;
int OutputToStdout = 0;
int UseColor = 0;
opterr = 0;
for (;;) {
int c = getopt(argc, argv, "d:s:t:7xoch");
/*
函数说明 getopt()用来分析命令行参数。
参数argc和argv是由main()传递的参数个数和内容。
参数optstring 则代表欲处理的选项字符串。
此函数会返回在argv 中下一个的选项字母,
此字母会对应参数optstring 中的字母。
如果选项字符串里的字母后接着冒号“:”,
则表示还有相关的参数,全域变量optarg
即会指向此额外参数。如果getopt()
找不到符合的参数则会印出错信息,
并将全域变量optopt设为“?”字符,
如果不希望getopt()印出错信息,
则只要将全域变量opterr设为0即可。
*/
if (c == -1)
break;
switch(c) {
case 'd':
DeviceName = optarg;
break;
case 't':
TtyName = optarg;
break;
case 's':
if (optarg[0] == 'd') {
DeviceSpeed = SerialSpeed(optarg + 1);
} else if (optarg[0] == 't') {
TtySpeed = SerialSpeed(optarg + 1);
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg);
break;
case 'o':
OutputToStdout = 1;
break;
case '7':
ByteBits = CS7;
break;
case 'x':
OutputHex = 1;
break;
case 'c':
UseColor = 1;
break;
case '?':
case 'h':
default:
PrintUsage();
}
}
if (optind != argc)
PrintUsage();//打印消息
CommFd = open(DeviceName, O_RDWR, 0);
if (CommFd < 0)
Error("Unable to open device");
if (fcntl(CommFd, F_SETFL, O_NONBLOCK) < 0)
Error("Unable set to NONBLOCK mode");
/*
F_SETFL 设置文件描述词状态旗标,
参数arg为新旗标,但只允许O_APPEND、
O_NONBLOCK和O_ASYNC位的改变,其他位的改变将不受影响。
O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O
*/
memset(&TtyAttr, 0, sizeof(struct termios));
/*
函数原型 void *memset(void *s, int ch, unsigned n);
将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值,
块的大小由第三个参数指定,这个函数通常为新申请的内存做初始化工作,
其返回值为指向S的指针。
将TtyAttr 所指向的内存区域的值全部设置为0 的Ascii值
*/
//设置串口的一些参数
TtyAttr.c_iflag = IGNPAR; //IGNPAR 忽略奇偶校验错误
//c_iflag:输入模式标志,控制终端输入方式,具体参数如表6.3所示。
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;
//CREAD 使用接收器 HUPCL 关闭设备时挂起 CLOCAL 忽略调制解调器线路状态
//c_cflag:控制模式标志,指定终端硬件控制信息,具体参数如表6.5所示。
TtyAttr.c_cc[VMIN] = 1; //VMIN 非规范模式读取时的最小字符数
//c_cc[NCCS]:控制字符,用于保存终端驱动程序中的特殊字符,
//如输入结束符等。c_cc中定义了如表6.7所示的控制字符。
if (tcsetattr(CommFd, TCSANOW, &TtyAttr) < 0)
Warning("Unable to set comm port");
/*
为了使程序控制终端参数,
在标准库中POSIX需要几个函数,
最重要的两个函数为tcsetattr和tcgetattr。
tcgetattr取回一个如图3-34中显示的数据结构的一份拷贝,
该结构为termios,它包含用来改变特殊字符、
设置模式和修改终端其他特性的所有信息。
程序可以检查当前的设置,
当需要时对这些设置进行修改,
然后调用tcsetattr把这个结构写回终端任务中。
头文件
<termios.h>
<unistd.h>
函数形式
int tcgetattr(int fd, struct termios *termios_p);
int tcsetattr(int fd, int optional_actions, const struct termios *termios_p);
*/
TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0); //ndelay 自我解释应该是延时的意思
if (TtyFd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;
if (tcgetattr(TtyFd, &BackupTtyAttr) < 0)
Error("Unable to get tty");
//BackupTtyAttr 用于存储获得的终端参数信息
if (tcsetattr(TtyFd, TCSANOW, &TtyAttr) < 0)
//使用tcsetattr函数将修改后的终端参数设置到标准输入中
Error("Unable to set tty");
for (;;) {
unsigned char Char = 0;
fd_set ReadSetFD;
void OutputStdChar(FILE *File)
{
char Buffer[10];
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", Char);
fwrite(Buffer, 1, Len, File);
}
/*
int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);
参数maxfd是需要监视的最大的文件描述符值+1;rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,
可写文件描述符的集 合及异常文件描述符的集合。struct timeval结构用于描述一段时间长度,如果在这个时间内,
需要监视的描述符没有事件发生则函数返回,返回值为0。
fd_set(它比较重要所以先介绍一下)是一组文件描述字(fd)的集合,
它用一位来表示一个fd(下面会仔细介绍),对于fd_set类型通过下面四个宏来操作:
FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,
在对文件描述符集合进行设置前,必须对其进行初始化,如果不清空,
由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。
过去,一个fd_set通常只能包含<32的fd(文件描述字),
因为fd_set其实只用了一个32位矢量来表示fd;现在,
UNIX系统通常会在头文件<sys/select.h>中定义常量FD_SETSIZE,
它是数据类型fd_set的描述字数量,其值通常是1024,这样就能表示<1024的fd。
根据fd_set的位矢量实现,我们可以重新理解操作fd_set的四个宏:
fd_set set;
FD_ZERO(&set);
FD_SET(0, &set);
FD_CLR(4, &set);
FD_ISSET(5, &set);
*/
FD_ZERO(&ReadSetFD);
FD_SET(CommFd, &ReadSetFD);
FD_SET( TtyFd, &ReadSetFD);
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {
Error(strerror(errno));
//检测可读的文件的文件描述符的集合
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {
/*
int FD_ISSET(int fd,fd_set *fdset)
宏说明:在调用select()函数后,用FD_ISSET来检测fdset中文件fd有无发生变化
*/
while (read(CommFd, &Char, 1) == 1) {
WaitFdWriteable(TtyFd);
//监控TtyFd这个文件描述符中是否有数据发生变化
//这个函数在上面有定义
// ssize_t write (int fd,const void * buf,size_t count);
//write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。
//当然,文件读写位置也会随之移动。
if (write(TtyFd, &Char, 1) < 0) {
Error(strerror(errno));
}
//如果用到了-O的属性 OutputTostdout 就会变成1就会输出下面的信息
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;34m", 1, 8, stdout);
OutputStdChar(stdout);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout);
fflush(stdout);
}
}
}
if (FD_ISSET(TtyFd, &ReadSetFD)) {
while (read(TtyFd, &Char, 1) == 1) {
static int EscKeyCount = 0;
WaitFdWriteable(CommFd);
if (write(CommFd, &Char, 1) < 0) {
Error(strerror(errno));
}
if (OutputToStdout) {
if (UseColor)
fwrite("\x1b[01;31m", 1, 8, stderr);
OutputStdChar(stderr);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stderr);
fflush(stderr);
}
if (Char == '\x1b') {
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
// 跳出到退出label
} else
EscKeyCount = 0;
}
}
}
ExitLabel:
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)
Error("Unable to set tty");
return 0;
另一种解析
作者: kissazi2
出处: http://www.cnblogs.com/kissazi2/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处: http://www.cnblogs.com/kissazi2/
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
/***************************************************************************
** 文件: comtest.c
** 描述:
** 以串口通讯的测试程序
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <termio.h> /*PPSIX 终端控制定义*/
#include <unistd.h>/*Unix 标准函数定义,使用exit()*/
#include <fcntl.h>/*文件控制定义*/
#include <getopt.h>/*参数提取定义*/
#include <time.h>
#include <errno.h>/*错误号定义*/
#include <string.h>
#include <assert.h>
int OutputHex = 0;//是否以十六进制发送。OutputHex为1时,以十六进制发送;为0,以字符串方式发送
int OutputToStdout = 0;//是否将消息同样发送一份到标准输出。为1时,发送;为0,不发送
int UseColor = 0; //是否使用颜色。为1时,使用颜色;为0,不使用颜色。
struct termios BackupTtyAttr;//终端属性的备份
int IsWrite=0;
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
static int SerialSpeed(const char *SpeedString)
{
int SpeedNumber = atoi(SpeedString);
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200);
TestSpeed(2400);
TestSpeed(4800);
TestSpeed(9600);
TestSpeed(19200);
TestSpeed(38400);
TestSpeed(57600);
TestSpeed(115200);
TestSpeed(230400);
Error("Bad speed");
return -1;
}
/**
*@brief 打印错误信息
*/
static void PrintUsage(void)
{
fprintf(stderr, "comtest - interactive program of comm port\n");
fprintf(stderr, "press [ESC] 3 times to quit\n\n");
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");
fprintf(stderr, " -7 7 bit\n");
fprintf(stderr, " -x hex mode\n");
fprintf(stderr, " -o output to stdout too\n");
fprintf(stderr, " -c stdout output use color\n");
fprintf(stderr, " -h print this help\n");
exit(-1);
}
/*******************************************************************************************************
** 函数: WaitFdWriteable, 等待文件可写
**------------------------------------------------------------------------------------------------------
** 参数: Fd 文件描述符
** 返回: void
** 函数说明:使用inline标识符,防止因为函数频繁的调用占用大量的栈空间
** 日期: 2013.06.19
********************************************************************************************************/
static inline void WaitFdWriteable(int Fd)
{
fd_set WriteSetFD; //定义可写的设备集合
FD_ZERO(&WriteSetFD);//将可写的设备集合清空
FD_SET(Fd, &WriteSetFD);//将fd添加到可写的设备集合中
//select函数原型: int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
//值得说明的是:int maxfdp是一个整数值,是指需要测试的文件描述符的数目,测试的描述符范围从0到nfds-1.即所有文件描述符的最大值加1,不能错!
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {//判断是否有可写的设备,如果没有就一直阻塞,这里没有设置超时,如果没有可写的,会一直阻塞下去
//select函数中readfds、errorfds描述符集合都为空,表示不进行测试
Error(strerror(errno));
}
}
void setAttrByArgvs(){
}
/*******************************************************************************************************
** 函数: OutputStdChar, 打开一个串口
**------------------------------------------------------------------------------------------------------
** 参数: FILE *File 文件描述符
int OutputHex,是否以十六进制发送。OutputHex为1时,以十六进制发送;为0,以字符串方式发送
unsigned char aCharToSend将要发送的字符
** 返回: void
**
** 日期: 2013.06.19
********************************************************************************************************/
void OutputStdChar(FILE *File,int OutputHex,unsigned char aCharToSend) {//向设备写数据
char Buffer[10];
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", aCharToSend);//%.2X表示输出01,02样式的十六进制数
// int Len = sprintf(Buffer, 0x01);//%.2X表示输出01,02样式的十六进制数
fwrite(Buffer, 1, Len, File);
}
/*******************************************************************************************************
** 函数: SetFD, 设置文件描述符
**------------------------------------------------------------------------------------------------------
** 参数:int argc
char **argv
int * CommFd 串口文件描述符
int * TtyFd 终端文件描述符
** 返回: void
**函数说明:
**本函数通过对main函数的argc、argv进行参数的提取,实现对串口文件描述符(CommFd)和终 端文件描述符TtyFd的设置
** 日期: 2013.06.19
********************************************************************************************************/
void SetFD(int argc, char **argv,int * CommFd,int * TtyFd){
struct termios TtyAttr; //终端属性
int DeviceSpeed = B2400; //串口波特率
int TtySpeed = B2400; //终端波特率
int ByteBits = CS8; //数据位:8位
const char *DeviceName = "/dev/ttySAC1";//串口设备名
const char *TtyName = "/dev/tty"; //终端设备名,防止重要的信息被用户重定向
opterr = 0;
printf("init........\n");
//通过Argc和Argv设置必要的参数
for (;;) {
int c = getopt(argc, argv, "d:s:t:7xoch");//利用getopt将argv参数一个个提取出来
if (c == -1)
break;
switch(c) {
case 'd'://设置串口的名称
DeviceName = optarg;
break;
case 't'://设置终端的名称
TtyName = optarg;
break;
case 's'://设置比特率
if (optarg[0] == 'd') {//设置串口的波特率
DeviceSpeed = SerialSpeed(optarg + 1);
} else if (optarg[0] == 't') {//设置终端的波特率
TtySpeed = SerialSpeed(optarg + 1);
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg);//如果没有带d或t,直接将两个设备的波特率设置成相同的
break;
case 'o'://设置同时将消息向标准输出(stdout)输出
OutputToStdout = 1;
break;
case '7'://设置数据位为7位
ByteBits = CS7;
break;
case 'x':
OutputHex = 1;//以十六进制输出
printf("OutputHex = 1\n");
break;
case 'c'://使用颜色标记
UseColor = 1;
break;
case '?':
case 'h':
default:
PrintUsage();//输出main参数的说明
}
}//end of for(;;)
printf("end of getopt\n");
if (optind != argc)//判断参数是否符合要求
PrintUsage(); //输出main参数的说明
*CommFd = open(DeviceName, O_RDWR, 0);//以读写的方式打开
if (*CommFd < 0)
Error("Unable to open device");//不能打开设备
if (fcntl(*CommFd, F_SETFL, O_NONBLOCK) < 0)//设置文件访问模式为非阻塞
Error("Unable set to NONBLOCK mode"); //不能使用NONBLOCK模式
memset(&TtyAttr, 0, sizeof(struct termios));
TtyAttr.c_iflag = IGNPAR;//忽略输入行中的中止状态
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;//DeviceSpeed:
//HUPCL:关闭时挂断调制解调器;CREAD:启用字符接收器;CLOCAL:忽略所有调制解调器的状态行
TtyAttr.c_cc[VMIN] = 1;//设置MIN值,read调用将一直等待,直到有MIN个字符可读的时候才返回,返回是读取的字符数量。到达文件结尾的时候返回0
if (tcsetattr(*CommFd, TCSANOW, &TtyAttr) < 0)//立即对属性进行修改,不等当前输出完成
Warning("Unable to set comm port");
*TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0);//只有在CTEAT模式下,才需要第三个参数,这边的第三个参数是没有作用的。
if (*TtyFd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;
if (tcgetattr(*TtyFd, &BackupTtyAttr) < 0)//将当前Tty的属性备份在BackupTtyAttr,以便在程序退出时还原Tty的设置
Error("Unable to get tty");
if (tcsetattr(*TtyFd, TCSANOW, &TtyAttr) < 0)
Error("Unable to set tty");
}
/*******************************************************************************************************
** 函数: OutputCharUseColor 输出带颜色的字符
**------------------------------------------------------------------------------------------------------
** 参数:char * colorCode 颜色代码
unsigned char aChar 要输出的字符
** 返回: void
** 日期: 2013.06.19
********************************************************************************************************/
void OutputCharUseColor(char * colorCode,unsigned char aChar){
if (OutputToStdout) { //同时向标准输出写消息
if (UseColor)
fwrite(colorCode, 1, 8, stdout);
OutputStdChar(stdout,OutputHex,aChar);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout);
fflush(stdout);//将stdout缓冲区中的数据立即输出,即在屏幕上显示
}
}
int uart_pthread(int argc, char **argv)
{
printf("into main\n");
int SendBufferIndex=0;
char * SendBuffer=(char *)malloc(sizeof(char)*20);//发送缓存
/**
TtyFD是为了防止与用户交互的信息被重定向,而没有在屏幕上显示。使用TtyFd可以直接将
不想被重定向的信息直接向用户终端(屏幕)输出。
**/
int CommFd, TtyFd; //串口、终端描述符
SetFD( argc, argv,&CommFd,&TtyFd);
for (;;) {
unsigned char aCharToSend = 0;
fd_set ReadSetFD; //可读设备集合
FD_ZERO(&ReadSetFD); //清空可读设备集合
FD_SET(CommFd, &ReadSetFD);//将串口加入可读设备集合
FD_SET( TtyFd, &ReadSetFD);//将终端加入可读设备集合
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )//最大值函数,返回两个数中较大的数
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {//同时测试串口和终端是否可读
Error(strerror(errno));
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {//判断串口是否可读
while (read(CommFd, &aCharToSend, 1) == 1) {//从串口中读取一个char型,放在aCharToSend
WaitFdWriteable(TtyFd);//会一直阻塞在这里,直到终端设备可写
if (write(TtyFd, &aCharToSend, 1) < 0) {//向屏幕输出收到的字符
Error(strerror(errno)); //如果写入错误,输出错误信息
}
OutputCharUseColor("\x1b[01;34m",aCharToSend);
}
}
// printf("------INTO if (FD_ISSET(TtyFd, &ReadSetFD)) ");
if (FD_ISSET(TtyFd, &ReadSetFD)) { //判断终端是否可读
while (read(TtyFd, &aCharToSend, 1) == 1) {//从终端中读取一个值
// fprintf(stderr,"\n------SendBufferIndex:%d ",SendBufferIndex);
SendBuffer[SendBufferIndex++]=aCharToSend;
// fprintf(stderr, "\nRead From Tty");
static int EscKeyCount = 0; //按下Esc的次数
OutputCharUseColor("\x1b[01;31m",aCharToSend);
if (aCharToSend == '\r') {//监测是否按下回车
SendBuffer[SendBufferIndex-1]='\0';
IsWrite=1;
fprintf(stderr, "\x1b[01;34m you have enter :%s\n \x1b[00m",SendBuffer);
// fprintf(stderr,"\n---11---IsWrite==%d ",IsWrite);
}
if(SendBufferIndex==19){
SendBuffer[SendBufferIndex]='\0';
// fprintf(stderr, "you have enter :%s\n",SendBuffer);
IsWrite=1;
}
if(IsWrite==1){
// fprintf(stderr,"\n------WaitFdWriteable ");
WaitFdWriteable(CommFd);
if (write(CommFd, SendBuffer, SendBufferIndex) < 0) {
Error(strerror(errno));
}
IsWrite=0;
SendBufferIndex=0;
}
if (aCharToSend == '\x1b') {//监测是否按下Esc
fprintf(stderr, "EscKeyPressed\x1b\n");
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
}else{
EscKeyCount = 0;
}
// fprintf(stderr,"\n---22---IsWrite==%d ",IsWrite);
}
}
}//end of for (;;)
ExitLabel:
free(SendBuffer);
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)//恢复之前终端的设置
Error("Unable to set tty");
return 0;
}
** 文件: comtest.c
** 描述:
** 以串口通讯的测试程序
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h> /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <termio.h> /*PPSIX 终端控制定义*/
#include <unistd.h>/*Unix 标准函数定义,使用exit()*/
#include <fcntl.h>/*文件控制定义*/
#include <getopt.h>/*参数提取定义*/
#include <time.h>
#include <errno.h>/*错误号定义*/
#include <string.h>
#include <assert.h>
int OutputHex = 0;//是否以十六进制发送。OutputHex为1时,以十六进制发送;为0,以字符串方式发送
int OutputToStdout = 0;//是否将消息同样发送一份到标准输出。为1时,发送;为0,不发送
int UseColor = 0; //是否使用颜色。为1时,使用颜色;为0,不使用颜色。
struct termios BackupTtyAttr;//终端属性的备份
int IsWrite=0;
static void Error(const char *Msg)
{
fprintf (stderr, "%s\n", Msg);
fprintf (stderr, "strerror() is %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
static void Warning(const char *Msg)
{
fprintf (stderr, "Warning: %s\n", Msg);
}
static int SerialSpeed(const char *SpeedString)
{
int SpeedNumber = atoi(SpeedString);
# define TestSpeed(Speed) if (SpeedNumber == Speed) return B##Speed
TestSpeed(1200);
TestSpeed(2400);
TestSpeed(4800);
TestSpeed(9600);
TestSpeed(19200);
TestSpeed(38400);
TestSpeed(57600);
TestSpeed(115200);
TestSpeed(230400);
Error("Bad speed");
return -1;
}
/**
*@brief 打印错误信息
*/
static void PrintUsage(void)
{
fprintf(stderr, "comtest - interactive program of comm port\n");
fprintf(stderr, "press [ESC] 3 times to quit\n\n");
fprintf(stderr, "Usage: comtest [-d device] [-t tty] [-s speed] [-7] [-c] [-x] [-o] [-h]\n");
fprintf(stderr, " -7 7 bit\n");
fprintf(stderr, " -x hex mode\n");
fprintf(stderr, " -o output to stdout too\n");
fprintf(stderr, " -c stdout output use color\n");
fprintf(stderr, " -h print this help\n");
exit(-1);
}
/*******************************************************************************************************
** 函数: WaitFdWriteable, 等待文件可写
**------------------------------------------------------------------------------------------------------
** 参数: Fd 文件描述符
** 返回: void
** 函数说明:使用inline标识符,防止因为函数频繁的调用占用大量的栈空间
** 日期: 2013.06.19
********************************************************************************************************/
static inline void WaitFdWriteable(int Fd)
{
fd_set WriteSetFD; //定义可写的设备集合
FD_ZERO(&WriteSetFD);//将可写的设备集合清空
FD_SET(Fd, &WriteSetFD);//将fd添加到可写的设备集合中
//select函数原型: int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
//值得说明的是:int maxfdp是一个整数值,是指需要测试的文件描述符的数目,测试的描述符范围从0到nfds-1.即所有文件描述符的最大值加1,不能错!
if (select(Fd + 1, NULL, &WriteSetFD, NULL, NULL) < 0) {//判断是否有可写的设备,如果没有就一直阻塞,这里没有设置超时,如果没有可写的,会一直阻塞下去
//select函数中readfds、errorfds描述符集合都为空,表示不进行测试
Error(strerror(errno));
}
}
void setAttrByArgvs(){
}
/*******************************************************************************************************
** 函数: OutputStdChar, 打开一个串口
**------------------------------------------------------------------------------------------------------
** 参数: FILE *File 文件描述符
int OutputHex,是否以十六进制发送。OutputHex为1时,以十六进制发送;为0,以字符串方式发送
unsigned char aCharToSend将要发送的字符
** 返回: void
**
** 日期: 2013.06.19
********************************************************************************************************/
void OutputStdChar(FILE *File,int OutputHex,unsigned char aCharToSend) {//向设备写数据
char Buffer[10];
int Len = sprintf(Buffer, OutputHex ? "%.2X " : "%c", aCharToSend);//%.2X表示输出01,02样式的十六进制数
// int Len = sprintf(Buffer, 0x01);//%.2X表示输出01,02样式的十六进制数
fwrite(Buffer, 1, Len, File);
}
/*******************************************************************************************************
** 函数: SetFD, 设置文件描述符
**------------------------------------------------------------------------------------------------------
** 参数:int argc
char **argv
int * CommFd 串口文件描述符
int * TtyFd 终端文件描述符
** 返回: void
**函数说明:
**本函数通过对main函数的argc、argv进行参数的提取,实现对串口文件描述符(CommFd)和终 端文件描述符TtyFd的设置
** 日期: 2013.06.19
********************************************************************************************************/
void SetFD(int argc, char **argv,int * CommFd,int * TtyFd){
struct termios TtyAttr; //终端属性
int DeviceSpeed = B2400; //串口波特率
int TtySpeed = B2400; //终端波特率
int ByteBits = CS8; //数据位:8位
const char *DeviceName = "/dev/ttySAC1";//串口设备名
const char *TtyName = "/dev/tty"; //终端设备名,防止重要的信息被用户重定向
opterr = 0;
printf("init........\n");
//通过Argc和Argv设置必要的参数
for (;;) {
int c = getopt(argc, argv, "d:s:t:7xoch");//利用getopt将argv参数一个个提取出来
if (c == -1)
break;
switch(c) {
case 'd'://设置串口的名称
DeviceName = optarg;
break;
case 't'://设置终端的名称
TtyName = optarg;
break;
case 's'://设置比特率
if (optarg[0] == 'd') {//设置串口的波特率
DeviceSpeed = SerialSpeed(optarg + 1);
} else if (optarg[0] == 't') {//设置终端的波特率
TtySpeed = SerialSpeed(optarg + 1);
} else
TtySpeed = DeviceSpeed = SerialSpeed(optarg);//如果没有带d或t,直接将两个设备的波特率设置成相同的
break;
case 'o'://设置同时将消息向标准输出(stdout)输出
OutputToStdout = 1;
break;
case '7'://设置数据位为7位
ByteBits = CS7;
break;
case 'x':
OutputHex = 1;//以十六进制输出
printf("OutputHex = 1\n");
break;
case 'c'://使用颜色标记
UseColor = 1;
break;
case '?':
case 'h':
default:
PrintUsage();//输出main参数的说明
}
}//end of for(;;)
printf("end of getopt\n");
if (optind != argc)//判断参数是否符合要求
PrintUsage(); //输出main参数的说明
*CommFd = open(DeviceName, O_RDWR, 0);//以读写的方式打开
if (*CommFd < 0)
Error("Unable to open device");//不能打开设备
if (fcntl(*CommFd, F_SETFL, O_NONBLOCK) < 0)//设置文件访问模式为非阻塞
Error("Unable set to NONBLOCK mode"); //不能使用NONBLOCK模式
memset(&TtyAttr, 0, sizeof(struct termios));
TtyAttr.c_iflag = IGNPAR;//忽略输入行中的中止状态
TtyAttr.c_cflag = DeviceSpeed | HUPCL | ByteBits | CREAD | CLOCAL;//DeviceSpeed:
//HUPCL:关闭时挂断调制解调器;CREAD:启用字符接收器;CLOCAL:忽略所有调制解调器的状态行
TtyAttr.c_cc[VMIN] = 1;//设置MIN值,read调用将一直等待,直到有MIN个字符可读的时候才返回,返回是读取的字符数量。到达文件结尾的时候返回0
if (tcsetattr(*CommFd, TCSANOW, &TtyAttr) < 0)//立即对属性进行修改,不等当前输出完成
Warning("Unable to set comm port");
*TtyFd = open(TtyName, O_RDWR | O_NDELAY, 0);//只有在CTEAT模式下,才需要第三个参数,这边的第三个参数是没有作用的。
if (*TtyFd < 0)
Error("Unable to open tty");
TtyAttr.c_cflag = TtySpeed | HUPCL | ByteBits | CREAD | CLOCAL;
if (tcgetattr(*TtyFd, &BackupTtyAttr) < 0)//将当前Tty的属性备份在BackupTtyAttr,以便在程序退出时还原Tty的设置
Error("Unable to get tty");
if (tcsetattr(*TtyFd, TCSANOW, &TtyAttr) < 0)
Error("Unable to set tty");
}
/*******************************************************************************************************
** 函数: OutputCharUseColor 输出带颜色的字符
**------------------------------------------------------------------------------------------------------
** 参数:char * colorCode 颜色代码
unsigned char aChar 要输出的字符
** 返回: void
** 日期: 2013.06.19
********************************************************************************************************/
void OutputCharUseColor(char * colorCode,unsigned char aChar){
if (OutputToStdout) { //同时向标准输出写消息
if (UseColor)
fwrite(colorCode, 1, 8, stdout);
OutputStdChar(stdout,OutputHex,aChar);
if (UseColor)
fwrite("\x1b[00m", 1, 8, stdout);
fflush(stdout);//将stdout缓冲区中的数据立即输出,即在屏幕上显示
}
}
int uart_pthread(int argc, char **argv)
{
printf("into main\n");
int SendBufferIndex=0;
char * SendBuffer=(char *)malloc(sizeof(char)*20);//发送缓存
/**
TtyFD是为了防止与用户交互的信息被重定向,而没有在屏幕上显示。使用TtyFd可以直接将
不想被重定向的信息直接向用户终端(屏幕)输出。
**/
int CommFd, TtyFd; //串口、终端描述符
SetFD( argc, argv,&CommFd,&TtyFd);
for (;;) {
unsigned char aCharToSend = 0;
fd_set ReadSetFD; //可读设备集合
FD_ZERO(&ReadSetFD); //清空可读设备集合
FD_SET(CommFd, &ReadSetFD);//将串口加入可读设备集合
FD_SET( TtyFd, &ReadSetFD);//将终端加入可读设备集合
# define max(x,y) ( ((x) >= (y)) ? (x) : (y) )//最大值函数,返回两个数中较大的数
if (select(max(CommFd, TtyFd) + 1, &ReadSetFD, NULL, NULL, NULL) < 0) {//同时测试串口和终端是否可读
Error(strerror(errno));
}
# undef max
if (FD_ISSET(CommFd, &ReadSetFD)) {//判断串口是否可读
while (read(CommFd, &aCharToSend, 1) == 1) {//从串口中读取一个char型,放在aCharToSend
WaitFdWriteable(TtyFd);//会一直阻塞在这里,直到终端设备可写
if (write(TtyFd, &aCharToSend, 1) < 0) {//向屏幕输出收到的字符
Error(strerror(errno)); //如果写入错误,输出错误信息
}
OutputCharUseColor("\x1b[01;34m",aCharToSend);
}
}
// printf("------INTO if (FD_ISSET(TtyFd, &ReadSetFD)) ");
if (FD_ISSET(TtyFd, &ReadSetFD)) { //判断终端是否可读
while (read(TtyFd, &aCharToSend, 1) == 1) {//从终端中读取一个值
// fprintf(stderr,"\n------SendBufferIndex:%d ",SendBufferIndex);
SendBuffer[SendBufferIndex++]=aCharToSend;
// fprintf(stderr, "\nRead From Tty");
static int EscKeyCount = 0; //按下Esc的次数
OutputCharUseColor("\x1b[01;31m",aCharToSend);
if (aCharToSend == '\r') {//监测是否按下回车
SendBuffer[SendBufferIndex-1]='\0';
IsWrite=1;
fprintf(stderr, "\x1b[01;34m you have enter :%s\n \x1b[00m",SendBuffer);
// fprintf(stderr,"\n---11---IsWrite==%d ",IsWrite);
}
if(SendBufferIndex==19){
SendBuffer[SendBufferIndex]='\0';
// fprintf(stderr, "you have enter :%s\n",SendBuffer);
IsWrite=1;
}
if(IsWrite==1){
// fprintf(stderr,"\n------WaitFdWriteable ");
WaitFdWriteable(CommFd);
if (write(CommFd, SendBuffer, SendBufferIndex) < 0) {
Error(strerror(errno));
}
IsWrite=0;
SendBufferIndex=0;
}
if (aCharToSend == '\x1b') {//监测是否按下Esc
fprintf(stderr, "EscKeyPressed\x1b\n");
EscKeyCount ++;
if (EscKeyCount >= 3)
goto ExitLabel;
}else{
EscKeyCount = 0;
}
// fprintf(stderr,"\n---22---IsWrite==%d ",IsWrite);
}
}
}//end of for (;;)
ExitLabel:
free(SendBuffer);
if (tcsetattr(TtyFd, TCSANOW, &BackupTtyAttr) < 0)//恢复之前终端的设置
Error("Unable to set tty");
return 0;
}
这篇关于友善之臂comtest.c串口编译程序详解 希望对大家有帮助的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!