Я пишу программу на C++ для связи с несколькими устройствами - Arduino Pro Mini w/ATmega328 и Arduino Uno с экраном GPS - одновременно через COM-порт , и я использую пакет boost :: asio. Я не гуру C++, поэтому я иногда путаюсь, пытаясь выяснить, где/когда нужно пройти по ссылке или значению; Я думаю, что это один из тех случаев.C++ boost asio serial communication «не может получить доступ к частному члену» в basic_serial_port.hpp
Вот код, который устанавливает последовательные порты для связи
std::string IMU_COM_PORT = "COM5"; // or whatever... it varies
int IMU_BAUD_RATE = 57600;
std::string ARDUINO_COM_PORT = "COM3"; // also varies
int ARDUINO_BAUD_RATE = 115200;
int main() {
std::vector<boost::thread *> sensorThreads;
int sensorThreadCount = 0;
using namespace::boost::asio;
// get the COM port handle for the IMU sensor
boost::asio::io_service IMU_io;
boost::asio::serial_port IMU_port(IMU_io);
IMU_port.open(IMU_COM_PORT);
if (!IMU_port.is_open()) {
cerr << "Failed to connect to IMU." << endl;
}
else {
IMU_port.set_option(boost::asio::serial_port_base::baud_rate(IMU_BAUD_RATE));
// the IMU has to be put into triggered output mode with a specific command: #o0
// to put it back into continuous output mode we can use this command: #o1
std::string IMU_init_cmd = "#o0";
boost::asio::write(IMU_port, boost::asio::buffer(IMU_init_cmd.c_str(), IMU_init_cmd.size()));
// now the IMU should be ready
sensorThreads.push_back(new boost::thread(testIMUThread, IMU_port));
sensorThreadCount++;
}
// get the COM port handle for the ARDUINO board with GPS sensor
boost::asio::io_service ARDUINO_io;
boost::asio::serial_port ARDUINO_port(ARDUINO_io);
ARDUINO_port.open(ARDUINO_COM_PORT);
if (!ARDUINO_port.is_open()) {
cerr << "Failed to connect to ARDUINO." << endl;
}
else {
ARDUINO_port.set_option(boost::asio::serial_port_base::baud_rate(ARDUINO_BAUD_RATE));
// now the ARDUINO w/GPS sensor should be ready
sensorThreads.push_back(new boost::thread(testGPSThread, ARDUINO_port));
sensorThreadCount++;
}
for (int i = 0; i < sensorThreadCount; i++) {
sensorThreads[i]->join();
delete sensorThreads[i];
}
}
Мои две функции испытания нити в основном идентичны, единственное отличие заключается в байт (а) они посылают к устройствам показывая, что что-то (мой компьютер) ждет, чтобы прочитать данные из них.
void testIMUThread(boost::asio::serial_port *port) {
while(true) { cout << readCOMLine(port, "#f") << endl; }
}
void testGPSThread(boost::asio::serial_port *port) {
while(true) { cout << readCOMLine(port, "r") << endl; }
}
И обе эти тестовые потоки используют одну функцию, которая выполняет последовательное чтение/запись.
std::string readCOMLine(boost::asio::serial_port *port, std::string requestDataCmd) {
char c;
std::string s;
boost::asio::write(port, boost::asio::buffer(requestDataCmd.c_str(), requestDataCmd.size()));
while(true) {
boost::asio::read(port, boost::asio::buffer(&c,1));
switch(c) {
case '\r': break;
case '\n': return s;
default: s += c;
}
}
}
Приведенный выше код не компилируется, но вместо этого производит следующее (в MSVC2010): Error 11 error C2248: 'boost::asio::basic_io_object<IoObjectService>::basic_io_object' : cannot access private member declared in class 'boost::asio::basic_io_object<IoObjectService>' C:\boost_1_51_0\boost\asio\basic_serial_port.hpp
Сообщение об ошибке довольно бесполезен - для меня, по крайней мере, - как я не был в состоянии отследить основную причину. Что мне здесь не хватает?
Благодарим за помощь.
Edit: Решения (благодаря Sam Miller)
Использование пройти по ссылке (т.е. boost::ref()
)
sensorThreads.push_back(new boost::thread(testIMUThread, IMU_port));
sensorThreads.push_back(new boost::thread(testIMUThread, ARDUINO_port));
в main()
стать
sensorThreads.push_back(new boost::thread(testIMUThread, boost::ref(IMU_port)));
sensorThreads.push_back(new boost::thread(testIMUThread, boost::ref(ARDUINO_port)));
Тогда лошадка и нить функция модифицирована такой
std::string readCOMLine(boost::asio::serial_port &port, std::string requestDataCmd) {
char c;
std::string s;
boost::asio::write(port, boost::asio::buffer(requestDataCmd.c_str(), requestDataCmd.size()));
while(true) {
boost::asio::read(port, boost::asio::buffer(&c,1));
switch(c) {
case '\r': break;
case '\n': return s;
default: s += c;
}
}
}
void testIMUThread(boost::asio::serial_port &port) {
while(true) { cout << readCOMLine(port, "#f") << endl; }
}
void testGPSThread(boost::asio::serial_port &port) {
while(true) { cout << readCOMLine(port, "r") << endl; }
}
С другой стороны, при использовании передачи по указателю, нить инициализация в main()
выглядеть следующим образом
sensorThreads.push_back(new boost::thread(testIMUThread, &IMU_port));
sensorThreads.push_back(new boost::thread(testIMUThread, &ARDUINO_port));
И функция резьбы например,
void testIMUThread(boost::asio::serial_port *port) {
while(true) { cout << readCOMLine(port, "#f") << endl; }
}
void testGPSThread(boost::asio::serial_port *port) {
while(true) { cout << readCOMLine(port, "r") << endl; }
}
Но я должен внести некоторые дополнительные изменения (поверх модификации входных параметров) в функцию, выполняющую al l работы - а именно, вызовы чтения/записи.
std::string readCOMLine(boost::asio::serial_port *port, std::string requestDataCmd) {
char c;
std::string s;
port->write_some(boost::asio::buffer(requestDataCmd.c_str(), requestDataCmd.size())); // this line
while(true) {
port->read_some(boost::asio::buffer(&c,1)); // and this line
switch(c) {
case '\r': break;
case '\n': return s;
default: s += c;
}
}
}
Оба решения скомпилированы и, похоже, работают для моих целей.
Спасибо!
Эй, Сэм, спасибо за ваш ответ. Одна из моих первоначальных попыток решить проблему состояла в том, чтобы передать указатель '& IMU_port', но мне нужно изменить код, который использует указатель (т.е.' asio :: write (port, buffer) 'становится' port-> write_some (буфер) '). Наверное, я тоже что-то не так понял, потому что я тоже не мог работать. С вашими примерами я понял это, хотя - оба метода. Спасибо! – Etan