Hello, I have some problem using the libboost asio to communicate with serial port. I want to open my serial port with : m_Balance.open(BalancePort, (unsigned int)9600, boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::even), boost::asio::serial_port_base::character_size((unsigned int)7), boost::asio::serial_port_base::flow_control( boost::asio::serial_port_base::flow_control::hardware), boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one)); but I have an exception with the character_size : Invalid Argument I put some log in the open method and I have found that my problem is on the set_option of the character size. Can someone help me? Thanks a lot. Mike Libboost is on Debian Wheezy : version 1.49 I use the following Serial Class (cpp) : /* * File: Serial.cpp * Author: Terraneo Federico * Distributed under the Boost Software License, Version 1.0. * Created on September 12, 2009, 3:47 PM * * v1.05: Fixed a bug regarding reading after a timeout (again). * * v1.04: Fixed bug with timeout set to zero * * v1.03: Fix for Mac OS X, now fully working on Mac. * * v1.02: Code cleanup, speed improvements, bug fixes. * * v1.01: Fixed a bug that caused errors while reading after a timeout. * * v1.00: First release. */ #include "Serial.h" #include <string> #include <algorithm> #include <iostream> #include <boost/bind.hpp> using namespace std; using namespace boost; CSerial::CSerial(): io(), port(io), timer(io), timeout(posix_time::seconds(0)) {} CSerial::CSerial(const std::string& devname, unsigned int baud_rate, asio::serial_port_base::parity opt_parity, asio::serial_port_base::character_size opt_csize, asio::serial_port_base::flow_control opt_flow, asio::serial_port_base::stop_bits opt_stop) : io(), port(io), timer(io), timeout(posix_time::seconds(0)) { open(devname,baud_rate,opt_parity,opt_csize,opt_flow,opt_stop); } void CSerial::open(const std::string& devname, unsigned int baud_rate, asio::serial_port_base::parity opt_parity, asio::serial_port_base::character_size opt_csize, asio::serial_port_base::flow_control opt_flow, asio::serial_port_base::stop_bits opt_stop) { if(isOpen()) close(); port.open(devname); Log.AddLine("set 1", LOG_DEBUG); port.set_option(asio::serial_port_base::baud_rate(baud_rate)); Log.AddLine("set 2", LOG_DEBUG); port.set_option(opt_parity); Log.AddLine("set 3", LOG_DEBUG); port.set_option(opt_csize); Log.AddLine("set 4", LOG_DEBUG); port.set_option(opt_flow); Log.AddLine("set 5", LOG_DEBUG); port.set_option(opt_stop); Log.AddLine("set 6", LOG_DEBUG); } bool CSerial::isOpen() const { return port.is_open(); } void CSerial::close() { if(isOpen()==false) return; port.close(); } void CSerial::setTimeout(const posix_time::time_duration& t) { timeout=t; } void CSerial::write(const char *data, size_t size) { asio::write(port,asio::buffer(data,size)); } void CSerial::write(const std::vector<char>& data) { asio::write(port,asio::buffer(&data[0],data.size())); } void CSerial::writeString(const std::string& s) { asio::write(port,asio::buffer(s.c_str(),s.size())); } void CSerial::read(char *data, size_t size) { if(readData.size()>0)//If there is some data from a previous read { istream is(&readData); size_t toRead=min(readData.size(),size);//How many bytes to read? is.read(data,toRead); data+=toRead; size-=toRead; if(size==0) return;//If read data was enough, just return } setupParameters=ReadSetupParameters(data,size); performReadSetup(setupParameters); //For this code to work, there should always be a timeout, so the //request for no timeout is translated into a very long timeout if(timeout!=posix_time::seconds(0)) timer.expires_from_now(timeout); else timer.expires_from_now(posix_time::hours(100000)); timer.async_wait(boost::bind(&CSerial::timeoutExpired,this, asio::placeholders::error)); result=resultInProgress; bytesTransferred=0; for(;;) { io.run_one(); switch(result) { case resultSuccess: timer.cancel(); return; case resultTimeoutExpired: port.cancel(); throw(timeout_exception("Timeout expired")); case resultError: timer.cancel(); port.cancel(); throw(boost::system::system_error(boost::system::error_code(), "Error while reading")); //if resultInProgress remain in the loop } } } std::vector<char> CSerial::read(size_t size) { vector<char> result(size,'\0');//Allocate a vector with the desired size read(&result[0],size);//Fill it with values return result; } std::string CSerial::readString(size_t size) { string result(size,'\0');//Allocate a string with the desired size read(&result[0],size);//Fill it with values return result; } std::string CSerial::readStringUntil(const std::string& delim) { // Note: if readData contains some previously read data, the call to // async_read_until (which is done in performReadSetup) correctly handles // it. If the data is enough it will also immediately call readCompleted() setupParameters=ReadSetupParameters(delim); performReadSetup(setupParameters); //For this code to work, there should always be a timeout, so the //request for no timeout is translated into a very long timeout if(timeout!=posix_time::seconds(0)) timer.expires_from_now(timeout); else timer.expires_from_now(posix_time::hours(100000)); timer.async_wait(boost::bind(&CSerial::timeoutExpired,this, asio::placeholders::error)); result=resultInProgress; bytesTransferred=0; for(;;) { io.run_one(); switch(result) { case resultSuccess: { timer.cancel(); bytesTransferred-=delim.size();//Don't count delim istream is(&readData); string result(bytesTransferred,'\0');//Alloc string is.read(&result[0],bytesTransferred);//Fill values is.ignore(delim.size());//Remove delimiter from stream return result; } case resultTimeoutExpired: port.cancel(); throw(timeout_exception("Timeout expired")); case resultError: timer.cancel(); port.cancel(); throw(boost::system::system_error(boost::system::error_code(), "Error while reading")); //if resultInProgress remain in the loop } } } CSerial::~CSerial() {} void CSerial::performReadSetup(const ReadSetupParameters& param) { if(param.fixedSize) { asio::async_read(port,asio::buffer(param.data,param.size),boost::bind( &CSerial::readCompleted,this,asio::placeholders::error, asio::placeholders::bytes_transferred)); } else { asio::async_read_until(port,readData,param.delim,boost::bind( &CSerial::readCompleted,this,asio::placeholders::error, asio::placeholders::bytes_transferred)); } } void CSerial::timeoutExpired(const boost::system::error_code& error) { if(!error && result==resultInProgress) result=resultTimeoutExpired; } void CSerial::readCompleted(const boost::system::error_code& error, const size_t bytesTransferred) { if(!error) { result=resultSuccess; this->bytesTransferred=bytesTransferred; return; } //In case a asynchronous operation is cancelled due to a timeout, //each OS seems to have its way to react. #ifdef _WIN32 if(error.value()==995) return; //Windows spits out error 995 #elif defined(__APPLE__) if(error.value()==45) { //Bug on OS X, it might be necessary to repeat the setup //http://osdir.com/ml/lib.boost.asio.user/2008-08/msg00004.html performReadSetup(setupParameters); return; } #else //Linux if(error.value()==125) return; //Linux outputs error 125 #endif result=resultError; } Serial.h /* * File: Serial.h * Author: Terraneo Federico * Distributed under the Boost Software License, Version 1.0. * * Created on September 12, 2009, 3:47 PM */ #ifndef Serial_H #define Serial_H #include <stdexcept> #include <boost/utility.hpp> #include <boost/asio.hpp> #include "Log.h" /** * Thrown if timeout occurs */ class timeout_exception: public std::runtime_error { public: timeout_exception(const std::string& arg): runtime_error(arg) {} }; /** * Serial port class, with timeout on read operations. */ class CSerial: private boost::noncopyable { public: CSerial(); /** * Opens a serial device. By default timeout is disabled. * \param devname serial device name, example "/dev/ttyS0" or "COM1" * \param baud_rate serial baud rate * \param opt_parity serial parity, default none * \param opt_csize serial character size, default 8bit * \param opt_flow serial flow control, default none * \param opt_stop serial stop bits, default 1 * \throws boost::system::system_error if cannot open the * serial device */ CSerial(const std::string& devname, unsigned int baud_rate, boost::asio::serial_port_base::parity opt_parity= boost::asio::serial_port_base::parity( boost::asio::serial_port_base::parity::none), boost::asio::serial_port_base::character_size opt_csize= boost::asio::serial_port_base::character_size(8), boost::asio::serial_port_base::flow_control opt_flow= boost::asio::serial_port_base::flow_control( boost::asio::serial_port_base::flow_control::none), boost::asio::serial_port_base::stop_bits opt_stop= boost::asio::serial_port_base::stop_bits( boost::asio::serial_port_base::stop_bits::one)); /** * Opens a serial device. * \param devname serial device name, example "/dev/ttyS0" or "COM1" * \param baud_rate serial baud rate * \param opt_parity serial parity, default none * \param opt_csize serial character size, default 8bit * \param opt_flow serial flow control, default none * \param opt_stop serial stop bits, default 1 * \throws boost::system::system_error if cannot open the * serial device */ void open(const std::string& devname, unsigned int baud_rate, boost::asio::serial_port_base::parity opt_parity= boost::asio::serial_port_base::parity( boost::asio::serial_port_base::parity::none), boost::asio::serial_port_base::character_size opt_csize= boost::asio::serial_port_base::character_size(8), boost::asio::serial_port_base::flow_control opt_flow= boost::asio::serial_port_base::flow_control( boost::asio::serial_port_base::flow_control::none), boost::asio::serial_port_base::stop_bits opt_stop= boost::asio::serial_port_base::stop_bits( boost::asio::serial_port_base::stop_bits::one)); /** * \return true if serial device is open */ bool isOpen() const; /** * Close the serial device * \throws boost::system::system_error if any error */ void close(); /** * Set the timeout on read/write operations. * To disable the timeout, call setTimeout(boost::posix_time::seconds(0)); */ void setTimeout(const boost::posix_time::time_duration& t); /** * Write data * \param data array of char to be sent through the serial device * \param size array size * \throws boost::system::system_error if any error */ void write(const char *data, size_t size); /** * Write data * \param data to be sent through the serial device * \throws boost::system::system_error if any error */ void write(const std::vector<char>& data); /** * Write a string. Can be used to send ASCII data to the serial device. * To send binary data, use write() * \param s string to send * \throws boost::system::system_error if any error */ void writeString(const std::string& s); /** * Read some data, blocking * \param data array of char to be read through the serial device * \param size array size * \return numbr of character actually read 0<=return<=size * \throws boost::system::system_error if any error * \throws timeout_exception in case of timeout */ void read(char *data, size_t size); /** * Read some data, blocking * \param size how much data to read * \return the receive buffer. It iempty if no data is available * \throws boost::system::system_error if any error * \throws timeout_exception in case of timeout */ std::vector<char> read(size_t size); /** * Read a string, blocking * Can only be used if the user is sure that the serial device will not * send binary data. For binary data read, use read() * The returned string is empty if no data has arrived * \param size hw much data to read * \return a string with the received data. * \throws boost::system::system_error if any error * \throws timeout_exception in case of timeout */ std::string readString(size_t size); /** * Read a line, blocking * Can only be used if the user is sure that the serial device will not * send binary data. For binary data read, use read() * The returned string is empty if the line delimiter has not yet arrived. * \param delimiter line delimiter, default="\n" * \return a string with the received data. The delimiter is removed from * the string. * \throws boost::system::system_error if any error * \throws timeout_exception in case of timeout */ std::string readStringUntil(const std::string& delim="\n"); ~CSerial(); private: /** * Parameters of performReadSetup. * Just wrapper class, no encapsulation provided */ class ReadSetupParameters { public: ReadSetupParameters(): fixedSize(false), delim(""), data(0), size(0) {} explicit ReadSetupParameters(const std::string& delim): fixedSize(false), delim(delim), data(0), size(0) { } ReadSetupParameters(char *data, size_t size): fixedSize(true), delim(""), data(data), size(size) { } //Using default copy constructor, operator= bool fixedSize; ///< True if need to read a fixed number of parameters std::string delim; ///< String end delimiter (valid if fixedSize=false) char *data; ///< Pointer to data array (valid if fixedSize=true) size_t size; ///< Array size (valid if fixedSize=true) }; /** * This member function sets up a read operation, both reading a specified * number of characters and reading until a delimiter string. */ void performReadSetup(const ReadSetupParameters& param); /** * Callack called either when the read timeout is expired or canceled. * If called because timeout expired, sets result to resultTimeoutExpired */ void timeoutExpired(const boost::system::error_code& error); /** * Callback called either if a read complete or read error occurs * If called because of read complete, sets result to resultSuccess * If called because read error, sets result to resultError */ void readCompleted(const boost::system::error_code& error, const size_t bytesTransferred); /** * Possible outcome of a read. Set by callbacks, read from main code */ enum ReadResult { resultInProgress, resultSuccess, resultError, resultTimeoutExpired }; boost::asio::io_service io; ///< Io service object boost::asio::serial_port port; ///< Serial port object boost::asio::deadline_timer timer; ///< Timer for timeout boost::posix_time::time_duration timeout; ///< Read/write timeout boost::asio::streambuf readData; ///< Holds eventual read but not consumed enum ReadResult result; ///< Used by read with timeout size_t bytesTransferred; ///< Used by async read callback ReadSetupParameters setupParameters; ///< Global because used in the OSX fix }; #endif //CSerial_H -- [logo Aston] MIKAEL PLOUHINEC miplouhinec@sqli.com T�l : +33(0) 2 51 79 77 40 - Mob : +33(0) 6 80 23 21 28 www.sqli.com - www.aston-ecole.com