我有一个通过USB连接到/dev/ttyACM0
的设备(旋转测量台),并且需要编写一个简单的cpp控制器以将命令发送到该设备并监听响应。
我没有这类经验。我了解我可以使用fstream
打开USB设备并使用write()
发送命令。可行。
问题是如何发送命令并开始侦听响应?
下面的代码只是挂起。我猜是因为它是同步的,因此错过了响应。
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::fstream f;
char command[256] = "?ASTAT\n\r";
char response[256];
std::string str;
f.open("/dev/ttyACM0");
if (f.is_open())
{
std::cout << "Port opened" << std::endl;
}
f.write(command, 256);
while(1)
{
while (f >> str)
{
std::cout << str;
}
}
return 0;
}
我研究了异步libusb-1.0,但在绕过http://libusb.sourceforge.net/api-1.0/group__libusb__asyncio.html并确定从哪里开始时遇到了问题。
编辑: 我设法使设备响应如下:
std::string response_value = "";
char response = 0;
std::cout << "response: ";
while(1)
{
f << command;
f.read(&response, 1);
if ((int)response == 13)
{
break;
}
std::cout << (response) << " ";
response_value += response;
}
与生产者交谈并尝试了不同的命令并输出消息后,我发现设备应发送可变长度响应,该响应始终以0x0D
或整数13结尾。
当前,如果我互相发送多个命令,则什么也没有发生。 从其他来源得知,我需要设置波特率,但是,fstream没有文件描述符,`tcgetattr(2)1重新启用文件描述符以初始化termios结构。有没有办法找回它?
答案 0 :(得分:0)
尽我所能回答这个问题。可以将USB设备读/写为文件,因为os具有正在处理通信的驱动程序(如果我理解错误,请更正我)。
fstream能够读取和写入,但是无法调整波特率(设备通信的频率),因为调整必须在终端级别进行,因此取决于os。对于Linux,我们必须使用fctl.h
,termios.h
和unistd.h
。它使我们可以设置速率,以及在设备无响应的情况下的超时。
因此,仅使用cpp函数实现读取和写入要复杂得多。
我在这里发布了适用于我的解决方案,但欢迎对此发表任何评论。
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <string>
#include <iostream>
bool init_terminal_interface(struct termios& tty, const int file_descriptor)
{
memset(&tty, 0, sizeof tty); // Init the structure;
if (tcgetattr(file_descriptor, &tty) != 0)
{
std::cout << "Error" << errno << " from tcgetattr: " << strerror(errno) << std::endl;
return false;
}
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag &= ~ICANON;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 0; //
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
/* Flush Port, then applies attributes */
tcflush(file_descriptor, TCIFLUSH);
if (tcsetattr(file_descriptor, TCSANOW, &tty) != 0) {
std::cout << "Error " << " from tcsetattr: " << strerror(errno) << std::endl;
return false;
}
return true;
}
void send_command(std::string command, const int file_descriptor)
{
write(file_descriptor, command.c_str(), command.size());
std::cout << "Command sent: " << command << std::endl;
}
std::string check_response(int file_descriptor)
{
std::string response_value = "";
char response = 0;
ssize_t n_read = 0;
do {
// In blocking mode, read() will return 0 after timeout.
n_read = read( file_descriptor, &response, 1 );
if (n_read > 0)
{
response_value += response;
}
} while( response != '\r' && (int)response != 13 && n_read != 0);
// In case of timeout it will return an empty string.
return response_value;
}
int open_serial(const std::string serial_path)
{
int file_descriptor = open(serial_path.c_str(), O_RDWR);
if (file_descriptor == -1)
{
std::cout << "Unable to access the turntable device." << std::endl;
return -1;
}
std::cout << "File opened: " << file_descriptor << std::endl;
struct termios tty;
init_terminal_interface(tty, file_descriptor);
return file_descriptor;
}
int main()
{
int file_descriptor = open_serial("/dev/ttyACM0");
if (file_descriptor == -1)
{
return 1;
}
// Good command.
std::string command = "?baudrate\r\n";
send_command(command, file_descriptor);
std::string response_value = check_response(file_descriptor);
std::cout << "Full response: " << response_value << std::endl;
// Wrong command.
command = "?asasdtat\r\n";
send_command(command, file_descriptor);
response_value = check_response(file_descriptor);
std::cout << "Full response: " << response_value << std::endl;
// Good command.
command = "init1\r\n";
send_command(command, file_descriptor);
response_value = check_response(file_descriptor);
std::cout << "Full response: " << response_value << std::endl;
// Good command.
command = "ref1=4\r\n";
send_command(command, file_descriptor);
response_value = check_response(file_descriptor);
std::cout << "Full response: " << response_value << std::endl;
return 0;
}