Serial port 如何在C程序中通过串行终端读取二进制数据?
我阅读了下面的链接和其他来源,但没有找到我问题的答案 我通过串行端口与嵌入式设备通信。默认情况下,嵌入式Linux将此端口用作终端。但是我想通过端口传输二进制数据(服务包)。我的/etc/inittab文件有一个“getty”调用: 控制台::重生:/sbin/getty 115200 ttyS0 我还有带字符串的/etc/passwd文件,其中“admin”用户在登录后启动我的“cli”应用程序: 管理员:8Mt/Jtxcyg8AY:1000:0:admin:/tmp:/tmp/cli 运行程序之前,我的默认ttyS0设置为:Serial port 如何在C程序中通过串行终端读取二进制数据?,serial-port,embedded-linux,binary-data,termios,Serial Port,Embedded Linux,Binary Data,Termios,我阅读了下面的链接和其他来源,但没有找到我问题的答案 我通过串行端口与嵌入式设备通信。默认情况下,嵌入式Linux将此端口用作终端。但是我想通过端口传输二进制数据(服务包)。我的/etc/inittab文件有一个“getty”调用: 控制台::重生:/sbin/getty 115200 ttyS0 我还有带字符串的/etc/passwd文件,其中“admin”用户在登录后启动我的“cli”应用程序: 管理员:8Mt/Jtxcyg8AY:1000:0:admin:/tmp:/tmp/cli 运
~ # stty -a
speed 115200 baud;stty: standard input
line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = ^J;
eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon ixoff
-iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon -iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt
-echoctl echoke
~ #
我尝试使用read()函数(使用无符号字符缓冲区)获取二进制数据,但未能接收正确的数据。我还初步再次打开/dev/ttyS0以获取文件描述符&使用read()func
我的程序发送3个字节:0xAA、0x02、0xFE。
但在syslog中,我总是看到设备接收到错误的符号:0x98、0xE6、0x18
怎么了?如何获得正确的二进制数据
我目前正在测试的整个代码。
#包括“cli.h”
#包括“glb_vars.h”
/******************************************
***定义
******************************************/
#定义应用程序名称“cli”
#定义SERIALPORT\u是\u控制台
/******************************************
***常数
******************************************/
const char dev_name[]=dev_name;
const char lineminstr[]=“\t----------------------------------------------------------------------\n”;
/******************************************
***内部函数声明
******************************************/
CLI_RETVAL cliInit(无效);
CLI_RETVAL cliClose(无效);
void cliWorkLoop(Term\u callback\u t**Term);
/******************************************
***外部函数声明
******************************************/
外部无效向量(术语**vec);
外部字符**菜单完成(常量字符*文本、整数开始、整数结束);
/****************************************************************************/
int file_descr,max_fd;
结构termios tty,原始;
fd_集工作_集;
/****************************************************************************/
/*!
*\brief Init cli
*
*\返回成功或失败
*\retval CLI\u成功,CLI\u失败
*
*\n组CLI
*/
/****************************************************************************/
CLI_RETVAL cliInit(无效)
{
长spd;
信号(信号,信号);
信号(信号灯、信号灯);
信号(SIGTERM,SIG_IGN);
信号(信号灯、信号灯);
信号(SIGQUIT,SIG_IGN);
信号机(信号机、信号机);
//系统(“stty-F/dev/ttyS0-icrnl-ixon-ixoff-opost-isig-icanon-echo”);//以非规范模式输入
//系统(“stty-a”);
//睡眠(1);
#ifdef串行端口是控制台
文件描述=STDIN\u文件编号;
系统日志调试(“串行端口是控制台”);
#否则
系统日志调试(“串行端口不是控制台”);
文件描述=打开(“/dev/ttyS0”,O_RDWR | O|u ASYNC | O|NDELAY);
如果(文件描述==-1){
//无法打开端口
perror(“无法打开/dev/ttyS0”);
出口(1);
}
#恩迪夫
如果(tcgetattr(文件描述和tty)<0)
{
perror(“无法获取tty属性”);
出口(1);
}
//备份tty,使其原始并应用更改
orig_tty=tty;
spd=B115200;
cfsetospeed(和tty,(速度)spd);
cfsetispeed(速度)spd(tty和tty);
cfmakeraw&tty;
tty.c_cc[VMIN]=1;
tty.c_cc[VTIME]=10;
tty.c_cflag&=~CSTOPB;
tty.c\u cflag&=~CRTSCTS;/*没有硬件流量控制*/
tty.c|u cflag |=CLOCAL | CREAD;
tcsetattr(文件描述、TCSANOW和tty);
////更新本地模式标志
//tty.c|lflag&=~(ICANON | ECHO | ECHO | ISIG);
//////更新控制模式标志
////tty.c|cflag&=~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD);
////tty.c|cflag |=(波特率|数据位|停止位|奇偶校验位|);
////选择“原始”输出模式
//tty.c_of lag&=~OPOST;
////禁用输入模式的映射
//tty.c|U iflag&=~(INLCR | ICRNL);
//
//
//if(tcsetattr(文件描述、TCSAFLUSH和tty)<0)
// {
//perror(“无法设置tty属性”);
//出口(1);
// }
//
//设置fd_集
FD_零(和工作集);
FD_集(文件描述和工作集);
max_fd=文件描述+1;
/*Readline lib init*/
//定义readline库的应用程序名称
rl_readline_name=应用程序_name;
//更新指向替代函数的指针以创建匹配项。
rl_尝试_完成_功能=菜单_完成;
//使用读取/etc/inputrc文件启动readline
使用_history();
扼杀历史(CLI_MAX_history_SIZE);
//其他一些初始化代码
// ...
// ...
返回cliu成功;
}
/****************************************************************************/
/*!
*\brief Close cli
*
*\返回成功或失败
*\retval CLI\u成功,CLI\u失败
*
*\n组CLI
*/
/****************************************************************************/
CLI_RETVAL cliClose(无效)
{
//系统(“stty-F/dev/ttyS0 icrnl ixon ixoff opost isig icanon echo”);//进入规范模式
tcsetattr(文件描述、TCSANOW和原始文档);
//if(tcsetattr(文件描述、TCSAFLUSH和源描述)<0)
// {
//perror(“无法设置原始属性”);
//出口(1);
// }
关闭(文件描述);
返回cliu成功;
}
/****************************************************************************/
/*!
*\brief主cli处理循环
*
*\不返回
*
*\n组CLI
*/
/****************************************************************************/
void cliWorkLoop(术语\u回调\u t**Term)
{
术语回调*cur\u术语;
int8*命令字符串;
uint8 ret=CLI\u刷新,无提示;
字符提示_str[20];
而(1){
cur_term=*term;
全局cmd\U compl\U指针=当前术语->cmd\U列表;
main ()
{
...
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter in non-canonical (raw) mode
// What function do I need to use here to retrieve binary data (also symbols that > 0x7F) from /dev/ttyS0?
system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); // go back to canonical mode
...
exit(0);
}
#include "cli.h"
#include "glb_vars.h"
/******************************************
*** Definitions
******************************************/
#define APPLICATION_NAME "cli"
#define SERIALPORT_IS_CONSOLE
/******************************************
*** Constants
******************************************/
const char dev_name[] = DEV_NAME;
const char lineminstr[] = "\t--------------------------------------------------------\n";
/******************************************
*** Internal Function Declarations
******************************************/
CLI_RETVAL cliInit(void);
CLI_RETVAL cliClose(void);
void cliWorkLoop(Term_callback_t **term);
/******************************************
*** External Function Declarations
******************************************/
extern void Vectors_init(Term_callback_t **vec);
extern char** Menu_completion(const char * text, int start, int end);
/****************************************************************************/
int file_descr, max_fd;
struct termios tty, orig_tty;
fd_set work_set;
/****************************************************************************/
/*!
* \brief Init cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliInit(void)
{
long spd;
signal(SIGINT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGABRT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGILL, SIG_IGN);
// system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter in non-canonical mode
// system("stty -a");
// sleep(1);
#ifdef SERIALPORT_IS_CONSOLE
file_descr = STDIN_FILENO;
SYS_LOG_DEBUG("SERIALPORT IS CONSOLE");
#else
SYS_LOG_DEBUG("SERIALPORT IS NOT CONSOLE");
file_descr = open("/dev/ttyS0", O_RDWR | O_ASYNC | O_NDELAY);
if (file_descr == -1) {
// Could not open the port
perror("unable to open /dev/ttyS0");
exit(1);
}
#endif
if(tcgetattr(file_descr, &tty) < 0)
{
perror("unable to get tty attributes");
exit(1);
}
// backup tty, make it raw and apply changes
orig_tty = tty;
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
tcsetattr(file_descr, TCSANOW, &tty);
// // update local mode flags
// tty.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//// // renew control mode flags
//// tty.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | PARODD);
//// tty.c_cflag |= (BAUD | DATABITS | STOPBITS | PARITYON | PARITY);
// // select 'raw' output mode
// tty.c_oflag &= ~OPOST;
// // disable mapping for input mode
// tty.c_iflag &= ~(INLCR | ICRNL);
//
//
// if(tcsetattr(file_descr, TCSAFLUSH, &tty) < 0)
// {
// perror("unable to set tty attributes");
// exit(1);
// }
//
// Setup fd_set
FD_ZERO(&work_set);
FD_SET(file_descr, &work_set);
max_fd = file_descr + 1;
/* Readline lib init */
// Define application name for readline library
rl_readline_name = APPLICATION_NAME;
// Update Pointer to alternative function to create matches.
rl_attempted_completion_function = Menu_completion;
// Start readline with reading /etc/inputrc file
using_history();
stifle_history(CLI_MAX_HISTORY_SIZE);
// Some other initialization code
// ...
// ...
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Close cli
*
* \return success or failure
* \retval CLI_SUCCESS, CLI_FAILURE
*
* \ingroup CLI
*/
/****************************************************************************/
CLI_RETVAL cliClose(void)
{
// system("stty -F /dev/ttyS0 icrnl ixon ixoff opost isig icanon echo"); // enter in canonical mode
tcsetattr(file_descr, TCSANOW, &orig_tty);
// if(tcsetattr(file_descr, TCSAFLUSH, &orig_tty) < 0)
// {
// perror("unable to set orig_tty attributes");
// exit(1);
// }
close(file_descr);
return CLI_SUCCESS;
}
/****************************************************************************/
/*!
* \brief Main cli processing loop
*
* \no return
*
* \ingroup CLI
*/
/****************************************************************************/
void cliWorkLoop(Term_callback_t **term)
{
Term_callback_t *cur_term;
int8 *commandString;
uint8 ret = CLI_REFRESH, no_prompt;
char prompt_str[20];
while (1) {
cur_term = *term;
global_cmd_compl_pointer = cur_term->cmd_list;
commandString = NULL;
sprintf(prompt_str, "%s:~> ", dev_name);
if(ret == CLI_REFRESH) {
CLEAR_SCR();
if(cur_term->out != NULL) {
cur_term->out(term, commandString, &ret);
no_prompt = ret;
}
CURSOR_DOWN();
}
int n;
struct timeval timeout;
uint8 tmpBuf[32];
while (1)
{
// Setup Timeout
timeout.tv_sec = 60;
timeout.tv_usec = 0;
// Wait for new connections
n = select(max_fd, &work_set, NULL, NULL, &timeout);
if (n < 0)
{
perror("select #2 failed");
break;
}
if (n > 0)
{
/* У нас есть ввод */
if (FD_ISSET(file_descr, &work_set))
{
if (read(file_descr, tmpBuf, 10) < 0) {
perror("cannot read");
exit(1);
}
else
{
SYS_LOG_DEBUG("READ first 4 chars: 0x%X,0x%X,0x%X,0x%X", tmpBuf[0], tmpBuf[1], tmpBuf[2], tmpBuf[3]);
}
}
break;
}
}
//
//
// n = read(file_descr, tmpBuf, 5);
// if (n > 0) {
// unsigned char *p = tmpBuf;
//
// while (n-- > 0)
// printf(" 0x%x", *p++);
// printf("\r\n");
// } else {
// printf("failed to read: %d\r\n", n);
// }
//
//
exit(0);
}
CLEAR_SCR();
return;
}
/****************************************************************************/
/*!
* \brief Main cli function
*
* \param[in] argc - argument number.
* \param[in,out] argv - argument values entered by user.
*
* \return success or failure
* \retval EXIT_SUCCESS, EXIT_FAILURE
*
*
* \ingroup CLI
*/
/****************************************************************************/
int main(int argc, char *argv[])
{
Term_callback_t *term;
char logname[16];
FILE *fp;
/* Set mask for file operation */
umask(0);
system("stty erase ^H");
openlog("cli", LOG_CONS, LOG_USER);
/* Write cli start log */
syslog(LOG_NOTICE, "Console startup. Software version: %s", VERSION);
/* Find login name */
strcpy(logname, "noname");
if ((fp = popen( "whoami", "r" )) == NULL)
{
SYS_LOG_ERR("Can't open process for \"whoami\" command.");
} else
{
fgets(logname, 16, fp);
pclose(fp);
}
SYS_LOG_INFO("Console is entered by \"%s\".", logname); //getenv("USER")
/* Console initialization */
if (cliInit() != CLI_SUCCESS) {
SYS_LOG_CRIT("CLI init failed");
return EXIT_FAILURE;
}
Vectors_init(&term);
/* Console work loop */
cliWorkLoop(&term);
cliClose();
/* Exiting from cli */
SYS_LOG_INFO("\"%s\" exited from console.", logname);
return EXIT_SUCCESS;
}
system("stty erase ^H);
system("stty -F /dev/ttyS0 -icrnl -ixon -ixoff -opost -isig -icanon -echo"); // enter into non-canonical (raw) mode
#include <stdio.h>
#include <stdlib.h>
#include <sys/un.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/syslog.h>
#include <termios.h>
#define SERIALPORT_IS_CONSOLE
main()
{
struct termios tty;
struct termios savetty;
speed_t spd;
unsigned int sfd;
unsigned char buf[80];
int reqlen = 79;
int rc;
int rdlen;
int pau = 0;
#ifdef SERIALPORT_IS_CONSOLE
sfd = STDIN_FILENO;
#else
sfd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
#endif
if (sfd < 0) {
syslog(LOG_DEBUG, "failed to open: %d, %s", sfd, strerror(errno));
exit (-1);
}
syslog(LOG_DEBUG, "opened sfd=%d for reading", sfd);
rc = tcgetattr(sfd, &tty);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to get attr: %d, %s", rc, strerror(errno));
exit (-2);
}
savetty = tty; /* preserve original settings for restoration */
spd = B115200;
cfsetospeed(&tty, (speed_t)spd);
cfsetispeed(&tty, (speed_t)spd);
cfmakeraw(&tty);
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 10;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS; /* no HW flow control? */
tty.c_cflag |= CLOCAL | CREAD;
rc = tcsetattr(sfd, TCSANOW, &tty);
if (rc < 0) {
syslog(LOG_DEBUG, "failed to set attr: %d, %s", rc, strerror(errno));
exit (-3);
}
do {
unsigned char *p = buf;
rdlen = read(sfd, buf, reqlen);
if (rdlen > 0) {
if (*p == '\r')
pau = 1;
syslog(LOG_DEBUG, "read: %d, 0x%x 0x%x 0x%x", \
rdlen, *p, *(p + 1), *(p + 2));
} else {
syslog(LOG_DEBUG, "failed to read: %d, %s", rdlen, strerror(errno));
}
} while (!pau);
tcsetattr(sfd, TCSANOW, &savetty);
close(sfd);
exit (0);
}
$ od -t x1 seq.bin
0000000 aa 02 fe
0000003
# tail /var/log/messages
Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3 FS on nvsram, internal journal
Sep xx xx:xx:42 atmel_soc user.info kernel: EXT3-fs: mounted filesystem with or.
Sep xx xx:xx:42 atmel_soc user.info kernel: kjournald starting. Commit intervas
Sep xx xx:xx:18 atmel_soc auth.info login[431]: root login on 'ttyS0'
Sep xx xx:xx:04 atmel_soc user.debug syslog: opened sfd=0 for reading
Sep xx xx:xx:14 atmel_soc user.debug syslog: read: 3, 0xaa 0x2 0xfe
Sep xx xx:xx:50 atmel_soc user.debug syslog: read: 1, 0x41 0x2 0xfe
Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x42 0x2 0xfe
Sep xx xx:xx:51 atmel_soc user.debug syslog: read: 1, 0x43 0x2 0xfe
Sep xx xx:xx:52 atmel_soc user.debug syslog: read: 1, 0xd 0x2 0xfe
#