Короткая версия:
- У меня был код A, позволяющий мне читать / записывать байты через последовательный порт (UART), который прошел модульное тестирование
- Я написал некоторый код B для чтения / записи байтов по TCP / IP с использованием boost asio (ну, технически, автономного asio), который также прошел модульное тестирование
- Когда я пытаюсь соединить A и B вместе,A начинает получать сообщения, когда ни одно из них не отправлено
- Я хочу знать, почему, и что я могу с этим сделать
Подробнее о коде A:
Код A - это в основном код C, использующий ioctl, fnctl и unistd.
Сначала я открываю сериал:
// Flag explanation:
// - O_RDWR
// = read & write
// (O_RDONLY = read-only)
// (O_WRONLY = write-only)
// - O_NOCTTY
// = if the path points to a terminal, that terminal will
// not become the controlling terminal for the process
// - O_NONBLOCK
// = read/write requests are non-blocking, and return failure status instead of waiting
_filestream = ::open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NONBLOCK);
После проверки того, что сериалбыл успешно открыт, я настраиваю UART
// Get options currently used by the USART
termios options;
tcgetattr(_filestream, &options);
// Set control options
{
// Set baudrate
cfsetispeed(&options, static_cast<speed_t>(baudrate));
cfsetospeed(&options, static_cast<speed_t>(baudrate));
// Enable receiver (those flags must always be set)
// CLOCAL = ignore modem status lines
// CREAD = enable receiver
options.c_cflag |= (CLOCAL | CREAD);
// Set character size
// CSIZE = bitmask for all sizes
// CS8 = specific flag for 8-bit
options.c_cflag &= ~static_cast<unsigned int>(CSIZE);
options.c_cflag |= CS8;
// Disable parity bit
// PARENB = parity enable flag
options.c_cflag &= ~static_cast<unsigned int>(PARENB);
// Set number of stop bits
// CSTOPB = use 2 stop bits insteqd of 1
options.c_cflag &= ~static_cast<unsigned int>(CSTOPB);
}
// Set local options
{
// Make sure to use raw input (pass character exactly as they are received)
// and not canonical input (which is line-oriented)
// ICANON = enable canonical input
// ECHO = enable echoing input characters
// ECHOE = make echo erases some characters
// ISIG = enable some signals
options.c_lflag &= ~static_cast<unsigned int>(ICANON | ECHO | ECHOE | ISIG);
}
// Set input options
{
// Enable software flow control
// IXON = Enable software flow control (outgoing)
// IXOFF = Enable software flow control (incoming)
// IXOFF = Allow any character to start flow again
options.c_iflag |= (IXON | IXOFF | IXANY);
}
// Set output options
{
// Choose raw output
// OPOST = choose postprocess output
options.c_oflag &= ~static_cast<unsigned int>(OPOST);
}
// Set options to use for the USART
// TCSANOW = change attributes immediately
tcsetattr(_filestream, TCSANOW, &options);
Чтобы записать материал в сериал, я делаю это:
int status = write(_filestream, &byte_array, array_size);
и просматриваю статус, чтобы убедиться, что все прошло хорошо.
Чтобы узнать, сколько байтов доступно для чтения, я делаю это:
int nbAvailable = 0;
ioctl(_filestream, FIONREAD, &nbAvailable);
Чтобы фактически прочитать эти байты, я делаюэто:
uint8_t c;
auto status = ::read(_filestream, &c, 1);
и посмотрите на статус, чтобы убедиться, что все прошло хорошо.
Когда я закончу, я просто закрою поток файлов:
close(_filestream);
Подробнее о коде B:
Не так много, чтобы сказать, сначала я делаю это:
asio::io_context _ioContext;
asio::ip::tcp::resolver::query query(remoteIP, remotePort);
asio::ip::tcp::resolver resolver (_ioContext);
asio::error_code errCode;
asio::ip::tcp::resolver::results_type _endPoints = resolver.resolve(query, errCode);
if (errCode)
{
std::cerr << "Cannot resolve IP/port for the connection" << std::endl;
exit(0);
}
Затем я подключаюсь вот так
asio::error_code errCode;
asio::connect(_socket, _endPoints, errCode);
if (!errCode)
{
launch_thread();
}
Сам поток представляет собой цикл, в котором байты считываются с использованием _socket.read_some()
, затем перемещаются в массив с защитой мьютекса или перемещаются из другого массива с защитой мьютекса, а затем отправляются с использованием _socket.write_some()
Что происходит, когда я соединяю два кода:
Устройство с последовательным портом в настоящий момент отключено, я ожидаю, что nbAvailable
будет 0 каждый раз, когда я проверяю, сколько байтовдоступны через последовательный порт, но это не так, и многие байты принимаются, когда их не должно быть.
Насколько я могу судить, это, кажется, результат asio
выполнения действийна сериал я использую. Это не так уж надумано, поскольку asio
также включает средства ввода-вывода с последовательным портом в дополнение к их средствам TCP / IP, и все свидетельства указывают на это:
- проблемы только возникаюткогда начинается соединение TCP / IP
- комментирование вызовов _socket.write_some () устраняет проблему
Что я хочу знать:
Почему asio
мешает моей связи через последовательный порт, когда я использую только его средства TCP / IP? Есть ли способ решить эту проблему?