Как настроить параметры term ios в C ++ для подключения Raspberry PI USB UART? - PullRequest
1 голос
/ 24 марта 2020

У меня есть RPI 3 и модуль LoRa USB, и я пишу код на C ++ для подключения порта к устройству. Я могу подключиться к порту (который назначен как ttyUSBPort1 в правиле udev). Однако, когда я отправляю данные в порт, я получаю сообщение об ошибке. Я просто недостаточно знаю термин ios и связь через порт, чтобы определить, в этом ли проблема (да, я прочитал справочную страницу).

Модуль LoRa - это устройство RN2903, и ниже приведено Инструкции по интерфейсу UART на справочном листе:

Все настройки и команды модуля RN2903 передаются по UART с использованием интерфейса ASCII. Все команды должны быть завершены с помощью (пробелы добавлены для форматирования) , и любые генерируемые ими ответы также будут завершаться в той же последовательности. Настройки по умолчанию для интерфейса UART: 57600 бит / с, 8 бит, без контроля четности, 1 стоп-бит, без контроля потока.

При отправке команд я вижу, что устройство отвечает «invalid_parameter» контролируя порт с помощью

sudo cat /dev/ttyUSBPort1

Я предполагаю, что некоторые из флагов термина ios установлены неправильно, или команда записи установлена ​​неправильно. Вот код, который у меня есть, который устанавливает порт:

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 ДД ГГГГ ЧЧ: ММ: СС, где XYZ - версия прошивки, МММ - месяц, ДД - день, ЧЧ: ММ: СС - час, минуты, секунды (формат: [HW] [FW] [Date] [Time]). [Дата] и [Время] относятся к выпуску прошивки. Эта команда возвращает информацию, относящуюся к аппаратной платформе, версии прошивки, дате выпуска и отметке времени при создании прошивки. Пример: sys get ver

На самом деле я получаю "invalid_param \ r \ n", который является соответствующим ответом от устройства, если в вызове что-то не так.

Есть идеи, где я могу ошибаться?

РЕДАКТИРОВАТЬ

благодаря Теду, который указал мне правильное направление и упростил мой код. Было два пропущенных флага ios. После того, как я установил эти (последние два), он работает нормально.

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());
}

1 Ответ

2 голосов
/ 24 марта 2020

Это создает 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 в настоящее время делает вашу программу неопределенным, это хорошее место для начала.

...