[英]How do i set up termios parameters in C++ for a Raspberry PI USB UART connection?
我有一個 RPI 3 和一個 LoRa USB 模塊,我正在用 C++ 編寫一些代碼來連接到設備的端口。 我能夠連接到端口(在 udev 規則中分配為 ttyUSBPort1)。 但是,當我向端口發送數據時,出現錯誤。 我只是對 termios 和端口通信知之甚少,無法確定這是否是問題所在(是的,我已經閱讀了聯機幫助頁)。
LoRa 模塊是 RN2903 設備,以下是參考表上的 UART 接口說明:
RN2903 模塊的所有設置和命令都使用 ASCII 接口通過 UART 傳輸。 所有命令都需要以 < CR >< LF > (為格式化添加空格)終止,並且它們生成的任何回復也將以相同的順序終止。 UART 接口的默認設置為 57600 bps、8 位、無奇偶校驗、1 個停止位、無流量控制。
發送命令時,我可以通過監視端口看到設備以“invalid_parameter”響應
sudo cat /dev/ttyUSBPort1
我假設我的某些 termios 標志設置不正確,或者 write 命令設置不正確。 這是我設置端口的代碼:
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;
}
這是從設備獲取版本信息的調用命令:
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);
}
寫入控制台 std::cout 時,我看到的是:
13 sys get ver
Writing to 3 Delay: 200000 Command Size: 13
表明消息確實被正確寫入。
設備的 cat 輸出應以如下方式響應(來自數據表):
2.3.6.1 sys get ver 響應:RN2903 XYZ MMM DD YYYY HH:MM:SS,其中XYZ為固件版本,MMM為月,DD為日,HH:MM:SS為時、分、秒(格式:[HW] ] [FW] [日期] [時間])。 [Date] 和 [Time] 是指固件的發布時間。 此命令返回與硬件平台、固件版本、發布日期和固件創建時間戳相關的信息。 示例:sys get ver
我實際得到的是“invalid_param\\r\\n”,如果呼叫中的某些內容不正確,這是來自設備的適當響應。
我在這里可能會出錯的任何想法?
編輯
感謝 Ted 為我指明了正確的方向並簡化了我的代碼。 有兩個缺失的 termios 標志。 一旦我設置了這些(最后兩個),它就可以正常工作。
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
新的寫調用函數:
void radioCMD(string cmd) {
cmd += "\r\n";
write(usb_port, cmd.c_str(), cmd.size());
}
這將創建一個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
}
更好的選擇是使用std::memcpy
而不是std::strcpy
來復制沒有空終止符的 C 字符串 - 並避免VLA
:s。
一個更好的選擇是直接使用你得到的std::string
作為參數:
void radioCMD(string cmd) {
cmd += "\r\n";
write(usb_port, cmd.c_str(), cmd.size());
}
這可能不是唯一的問題,但由於std::strcpy
當前使您的程序具有未定義的行為,因此這是一個很好的起點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.