为什么此串行/调制解调器代码弄乱了我的终端显示
Why does this serial/modem code mess up my terminal display?
我已经编写了一些代码,以基本上是使用Regex/dev/tty*在UNIX系统上找到任何调制解调器命令并检查响应消息是否包含字符"确定"。
代码确实找到了调制解调器,但不幸的是,它弄乱了终端显示屏。见下文。我注意到它也打印出AT命令 - 请参见下面的输出。为什么我的终端显示器更改了?我该如何解决?
运行程序后,如果输入命令并输入,例如LS,则未显示命令,但是当您按Enter时,您会看到输出。
这是代码:
#include <iostream>
#include <string>
#include <unordered_map>
#include <iomanip>
#include <memory>
#include <sstream>
#include <thread>
#include <iostream>
#include <filesystem>
#include <regex>
#include <unistd.h> // close
#include <fcntl.h> // open, O_RDWR, etc
#include <termios.h>
#include <string.h>
#include <sys/select.h> // timeouts for read
#include <sys/timeb.h> // measure time taken
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
// Error from tcgetattr - can use strerror(errno)
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
// Error from tcsetattr- use strerror(errno)
return -1;
}
return 0;
}
long enumerate_ports(std::unordered_map <std::string, std::string>& ports) {
// ls /dev | grep ^tty.*
const std::regex my_filter( "^tty.*" );
std::string path = "/dev/";
for (const auto & entry : std::filesystem::directory_iterator(path)) {
std::smatch sm;
std::string tmp = entry.path().filename().string();
// if we have a regex match attempt to open port and send AT command
if (std::regex_match(tmp, sm, my_filter)) {
std::string portname = entry.path().string();
int fd = ::open(portname.c_str(), O_RDWR | O_NOCTTY);
if (fd < 0) {
// Error opening port
continue;
} else {
// port was opened successfully
// try to write AT command and do we get an OK response
// baudrate 9600, 8 bits, no parity, 1 stop bit
if(set_interface_attribs(fd, B9600) != 0) {
::close(fd);
continue;
}
int wlen = ::write(fd, "ATrn", 4);
if (wlen != 4) {
// Error from write
::close(fd);
continue;
}
// tcdrain() waits until all output written to the object referred
// to by fd has been transmitted.
tcdrain(fd);
fd_set set;
struct timeval timeout;
FD_ZERO(&set); /* clear the set */
FD_SET(fd, &set); /* add our file descriptor to the set */
timeout.tv_sec = 0;
timeout.tv_usec = 100000; // 100 milliseconds
// wait for data to be read or timeout
int rv = select(fd + 1, &set, NULL, NULL, &timeout);
if(rv > 0) { // no timeout or error
unsigned char buf[80];
const int bytes_read = ::read(fd, buf, sizeof(buf) - 1);
if (bytes_read > 0) {
buf[bytes_read] = 0;
unsigned char* p = buf;
// scan for "OK"
for (int i = 0; i < bytes_read; ++i) {
if (*p == 'O' && i < bytes_read - 1 && *(p+1) == 'K') {
// we have a positive response from device so add to ports
ports[portname] = "";
break;
}
p++;
}
}
}
::close(fd);
}
}
}
return ports.size();
}
int main() {
struct timeb start, end;
int diff;
ftime(&start);
// get list of ports available on system
std::unordered_map <std::string, std::string> ports;
long result = enumerate_ports(ports);
std::cout << "No. found modems: " << result << std::endl;
for (const auto& item : ports) {
std::cout << item.first << "->" << item.second << std::endl;
}
ftime(&end);
diff = (int) (1000.0 * (end.time - start.time)
+ (end.millitm - start.millitm));
printf("Operation took %u millisecondsn", diff);
}
和输出:
acomber@mail:~/Documents/projects/modem/serial/gdbplay$ ls
main.cpp main.o Makefile serial
acomber@mail:~/Documents/projects/modem/serial/gdbplay$ make serial
g++ -Wall -Werror -ggdb3 -std=c++17 -pedantic -c main.cpp
g++ -o serial -Wall -Werror -ggdb3 -std=c++17 -pedantic main.o -L/usr/lib -lstdc++fs
acomber@mail:~/Documents/projects/modem/serial/gdbplay$ sudo ./serial
[sudo] password for acomber:
AT
No. found modems: 1
/dev/ttyACM0->
Operation took 8643 milliseconds
acomber@mail:~/Documents/projects/modem/serial/gdbplay$
为什么此串行/调制解调器代码弄乱了我的终端显示?
一个精确的答案要求您在执行代码之前发布终端的设置,即stty -a
。
代码确实找到了调制解调器,但不幸的是,它弄乱了终端显示屏。
最简单(即直接(解决方案/解决方案是遵守保存的旧(但很少遵循(的建议,然后恢复终端的术语设置,如本示例。
。代码中所需的简单更改将是(请忽略C和C 的混合;我只知道C(以下补丁。
struct termios savetty;
int set_interface_attribs(int fd, int speed)
{
+ struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
// Error from tcgetattr - can use strerror(errno)
return -1;
}
+ savetty = tty; /* preserve original settings for restoration */
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
然后在 emumerate_ports((中,需要用将执行修复的序列替换::close(fd);
的最后两个实例:
+ if (tcsetattr(fd, &savetty) < 0) {
+ // report cannot restore attributes
+ }
::close(fd);
运行程序后,如果输入命令并输入,例如LS,则未显示命令...
这显然是离开回波属性的结果。
"丢失"的马车退货可能是由于清除的OPOST。
您的程序清除但可能会被外壳设置的其他明显属性是Icanon,iCrnl和iexten。
但是,与其试图确定需要撤销的确切和保证的修复是简单地将术语设置恢复为原始状态。
执行程序后,一种替代方法(懒惰(方法将使用stty sane
命令。
相关文章:
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- clang整洁10忽略了我的NOLINT命令
- 反向功能超出了我的 cpp 程序的范围
- 为什么创建服务器后C++ httplib 库阻塞了我的主线程?
- 插入一个基本的单向链表节点似乎破坏了我的 c++ 代码?
- 错误:从"int"到"int*"的转换无效[-允许].我在下面提供了我的代码,我
- 谷歌测试发现在macOSX上添加并运行了我的所有测试两次
- 为什么STL优先级队列错误地分配了我的类对象
- 我需要做一个深度复制,我是否正确使用了我的复制构造函数?
- c_str() 只读取了我的字符串的一半,为什么?我该如何解决这个问题?是字节问题吗?
- 为什么QTableView扩展选择忽略了我的默认选择行
- 为什么Linux报告了我的应用程序的内存使用情况
- C++中的类/函数模板占用了我的二进制文件的百分比是多少?
- 为什么此串行/调制解调器代码弄乱了我的终端显示
- std::move 返回值 weak_ptr::锁定弄乱了shared_ptr的引用计数?
- QT在UI文件中恢复了我的更改
- 为什么虚拟功能打破了我的铸造
- <vector> 搞砸了我的快速排序
- MySQL C ++连接器在我插入数据库时减少了我的字符串
- 为什么返回数据结构而不是指针弄乱了我的数据的完整性