我閱讀後面的鏈接和其他來源,但沒有找到我的問題的答案。如何在C程序中通過串行終端讀取二進制數據?
Binary data over serial terminal
Data gets corrupted during transmission over the serial port
我通過串口與我的嵌入式設備的通信。默認情況下,嵌入式Linux使用此端口作爲終端。但我想通過端口傳輸二進制數據(服務數據包)。我的/ etc/inittab文件有一個 「格蒂」 電話: 控制檯::重生:/ sbin目錄/蓋蒂115200 ttyS0來
我也有串/ etc/passwd文件,其中 「admin」 用戶推出我的「CLI 「應用程序後登錄: 管理:8MT/Jtxcyg8AY:1000:0:管理員:/ tmp目錄:/ tmp目錄/ CLI
我的默認ttyS0來設置之前運行的程序是:
所以,在我的cli程序中,我執行以下操作:
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);
}
我試圖讀取()函數(與unsigned char緩衝區)來獲取二進制數據,但未能接收到正確的數據。我也初步打開/ dev/ttyS0來獲取file_descriptor &使用read()函數。
我的程序發送3個字節:0xAA,0x02,0xFE。 但在系統日誌中,我總是看到該設備接收不正確的符號:0x98,0xE6,0x18。
這是怎麼回事?如何獲取正確的二進制數據?
我正在測試的整個代碼。
#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;
}
您的串口設置爲規範輸入,即ASCII文本行。切換到*原始模式*或在兩端轉換二進制數據。查看'uuencode'和'uudecode'以通過ASCII介質傳輸二進制數據。這是以純文本電子郵件和USENET過帳發送二進制數據的傳統方式。發送二進制或「特殊」字符的另一種方法是使用「轉義」字符來前綴「特殊」字符,並將該字節標準化爲有效的ASCII字符。 BTW'-parenb -parodd cs8'將產生11位字符幀。使用8位數據字符時,「無奇偶校驗」是典型的。 – sawdust
謝謝你的木屑!你是對的,第二個變種是一個更方便的使用方法。但我有一箇舊的軟件與以前的嵌入式設備進行通信,並不支持它。我們很可能不得不改變它來支持一個新的。即使如此,爲什麼在使用read()函數進入原始模式時(請參閱提及的代碼),我無法獲得特殊字符? – Bakir