2013-04-26 1 views
1

Я пишу программу на 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; 
     } 
    } 
} 

Оба решения скомпилированы и, похоже, работают для моих целей.

Спасибо!

ответ

1

boost::asio::serial_port объекты noncopyable

Вы должны передать ссылку

sensorThreads.push_back(new boost::thread(testIMUThread, boost::ref(IMU_port))); 

или указатель

sensorThreads.push_back(new boost::thread(testIMUThread, &IMU_port)); 

вот coliru показывает обе методики.

+0

Эй, Сэм, спасибо за ваш ответ. Одна из моих первоначальных попыток решить проблему состояла в том, чтобы передать указатель '& IMU_port', но мне нужно изменить код, который использует указатель (т.е.' asio :: write (port, buffer) 'становится' port-> write_some (буфер) '). Наверное, я тоже что-то не так понял, потому что я тоже не мог работать. С вашими примерами я понял это, хотя - оба метода. Спасибо! – Etan

Смежные вопросы