发送命令并等待回复USB设备

时间:2019-02-15 16:41:50

标签: c++

我有一个通过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结构。有没有办法找回它?

1 个答案:

答案 0 :(得分:0)

尽我所能回答这个问题。可以将USB设备读/写为文件,因为os具有正在处理通信的驱动程序(如果我理解错误,请更正我)。 fstream能够读取和写入,但是无法调整波特率(设备通信的频率),因为调整必须在终端级别进行,因此取决于os。对于Linux,我们必须使用fctl.htermios.hunistd.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;
}