简体   繁体   English

如何在 C++ 中为 Raspberry PI USB UART 连接设置 termios 参数?

[英]How do i set up termios parameters in C++ for a Raspberry PI USB UART connection?

I have a RPI 3 and a LoRa USB module and I'm writing some code in C++ for the port connection to the device.我有一个 RPI 3 和一个 LoRa USB 模块,我正在用 C++ 编写一些代码来连接到设备的端口。 I am able to connect to the port (which is assigned as ttyUSBPort1 in a udev rule).我能够连接到端口(在 udev 规则中分配为 ttyUSBPort1)。 However when I am sending data to the port, I'm getting an error.但是,当我向端口发送数据时,出现错误。 I just don't know enough about termios and port communications to determine if that's the problem (yes, I've read the manpage).我只是对 termios 和端口通信知之甚少,无法确定这是否是问题所在(是的,我已经阅读了联机帮助页)。

The LoRa module is a RN2903 device and the following is the UART Interface instructions on the reference sheet: LoRa 模块是 RN2903 设备,以下是参考表上的 UART 接口说明:

All of the RN2903 module's settings and commands are transmitted over UART using the ASCII interface. RN2903 模块的所有设置和命令都使用 ASCII 接口通过 UART 传输。 All commands need to be terminated with < CR >< LF > (spaces added for formatting) and any replies they generate will also be terminated by the same sequence.所有命令都需要以 < CR >< LF > (为格式化添加空格)终止,并且它们生成的任何回复也将以相同的顺序终止。 The default settings for the UART interface are 57600 bps, 8 bits, no parity, 1 Stop bit, no flow control. UART 接口的默认设置为 57600 bps、8 位、无奇偶校验、1 个停止位、无流量控制。

When sending commands, I can see that the device is responding with "invalid_parameter" by monitoring the port with发送命令时,我可以通过监视端口看到设备以“invalid_parameter”响应

sudo cat /dev/ttyUSBPort1

I am assuming either I have some of the termios flags set incorrectly, or the write command set up incorrectly.我假设我的某些 termios 标志设置不正确,或者 write 命令设置不正确。 Here's the code I have that sets up the port:这是我设置端口的代码:

int openPort(void) {
struct termios tty;
memset(&tty, 0, sizeof tty);
if ((usb_port = open(device, O_RDWR))>=0) {// | O_NOCTTY | O_SYNC
    std::cout << "DEVICE OPENED: " << device << " handle number: " << usb_port << std::endl;
} else {
    fprintf(stderr, "unable to open serial device");
    return -1;
}
if(tcgetattr(usb_port, &tty) != 0) {
    printf("Error %i \n", errno);
}
cfsetispeed(&tty, B57600);
cfsetospeed(&tty, B57600);

tty.c_cflag     &=  ~PARENB;            // Make 8n1
tty.c_cflag     &=  ~CSTOPB;
tty.c_cflag     &=  ~CSIZE;
tty.c_cflag     |=  CS8;

tty.c_cflag     &=  ~CRTSCTS;           // no flow control
tty.c_cc[VMIN]   =  0;                  // read doesn't block
tty.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout

tcflush( usb_port, TCIFLUSH );
if (tcsetattr(usb_port, TCSANOW, &tty) != 0) {
    printf("Error %i\n", errno);
}
return usb_port;
}

And here's the call command to get the version information from the device:这是从设备获取版本信息的调用命令:

void radioCMD(string tmp) {
string tmp2 = tmp + "\r\n";
int n = tmp2.length();
char cmd[n];
strcpy(cmd, tmp2.c_str());
std::cout << write(usb_port, cmd, sizeof(cmd)) << " " << cmd << "Writing to " << usb_port << " Delay: " << delay << " Command Size: " << sizeof(cmd) << std::endl;
}
void setupRadio() {
radioCMD("sys get ver");
usleep(delay);
}

When writing to the console std::cout, I am seeing this:写入控制台 std::cout 时,我看到的是:

13 sys get ver
Writing to 3 Delay: 200000 Command Size: 13

showing that the message is indeed being correctly written.表明消息确实被正确写入。

The cat output from the device should respond with something like this (from the datasheet):设备的 cat 输出应以如下方式响应(来自数据表):

2.3.6.1 sys get ver Response: RN2903 XYZ MMM DD YYYY HH:MM:SS, where XYZ is the firmware version, MMM is month, DD is day, HH:MM:SS is hour, minutes, seconds (format: [HW] [FW] [Date] [Time]). 2.3.6.1 sys get ver 响应:RN2903 XYZ MMM DD YYYY HH:MM:SS,其中XYZ为固件版本,MMM为月,DD为日,HH:MM:SS为时、分、秒(格式:[HW] ] [FW] [日期] [时间])。 [Date] and [Time] refer to the release of the firmware. [Date] 和 [Time] 是指固件的发布时间。 This command returns the information related to the hardware platform, firmware version, release date and time-stamp on firmware creation.此命令返回与硬件平台、固件版本、发布日期和固件创建时间戳相关的信息。 Example: sys get ver示例:sys get ver

What I actually get is "invalid_param\\r\\n", which is the appropriate response from the device if something in the call is not correct.我实际得到的是“invalid_param\\r\\n”,如果呼叫中的某些内容不正确,这是来自设备的适当响应。

Any ideas where I might be going wrong here?我在这里可能会出错的任何想法?

EDIT编辑

thanks to Ted for pointing me in the right direction and simplifying my code.感谢 Ted 为我指明了正确的方向并简化了我的代码。 There were two missing termios flags.有两个缺失的 termios 标志。 Once I set these (last two), it works fine.一旦我设置了这些(最后两个),它就可以正常工作。

tty.c_cflag     &=  ~PARENB;            // Make 8n1
tty.c_cflag     &=  ~CSTOPB;
tty.c_cflag     &=  ~CSIZE;
tty.c_cflag     |=  CS8;
tty.c_cflag     &=  ~CRTSCTS;           // no flow control
tty.c_cc[VMIN]   =  0;                  // read doesn't block
tty.c_cc[VTIME]  =  5;                  // 0.5 seconds read timeout
        ***ADDITIONAL TWO FLAGS THAT FIXED IT****
tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
tty.c_oflag &= ~OCRNL; // Prevent conversion of newline to carriage return/line feed

New Write Call Function:新的写调用函数:

void radioCMD(string cmd) {
    cmd += "\r\n";
    write(usb_port, cmd.c_str(), cmd.size());
}

This creates a VLA that is one char too short to fit the null terminator of the C string:这将创建一个VLA是一个char过短,以适应C字符串的空终止:

void radioCMD(string tmp) {
    string tmp2 = tmp + "\r\n";
    int n = tmp2.length();
    char cmd[n];                       // should be n+1 for strcpy to work
    strcpy(cmd, tmp2.c_str());         // undefined behavior \0 is written out of bounds
    write(usb_port, cmd, sizeof(cmd)); // sizeof(cmd) should be replaced by n
}

A better alternative would be to use std::memcpy instead of std::strcpy to copy the C string without the null terminator - and to avoid VLA :s.更好的选择是使用std::memcpy而不是std::strcpy来复制没有空终止符的 C 字符串 - 并避免VLA :s。

An even better alternative would be to use the std::string you get as a parameter directly:一个更好的选择是直接使用你得到的std::string作为参数:

void radioCMD(string cmd) {
    cmd += "\r\n";
    write(usb_port, cmd.c_str(), cmd.size());
}

It may not be the only problem, but as the std::strcpy currently makes your program have undefined behavior, it's a good place to start.这可能不是唯一的问题,但由于std::strcpy当前使您的程序具有未定义的行为,因此这是一个很好的起点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM