00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <RmpUsb.h>
00040
00041 #include <exception>
00042
00043 #include <boost/asio.hpp>
00044 #include <boost/bind.hpp>
00045 #include <boost/date_time/posix_time/posix_time_types.hpp>
00046
00047 #include <RmpHelper.h>
00048 #include <RmpLogger.h>
00049
00050 namespace segway
00051 {
00052 static const size_t MAX_RCV_SIZE = 1024;
00053 static const long TIMEOUT = 30;
00054 static const unsigned int BAUD_RATE = 115200;
00055 static const unsigned int CHARACTER_SIZE = 8;
00056
00057 class RmpUsb::Impl
00058 {
00059 public:
00060 Impl(const std::string& rDevicePort);
00061 size_t Write(const Bytes& rData, float timeout, boost::system::error_code& rErrorCode);
00062 size_t Read(Bytes& rData, float timeout, boost::system::error_code& rErrorCode);
00063
00064 private:
00065 void CheckDeadline();
00066 static void Handle(const boost::system::error_code& rErrorCodeIn, size_t sizeIn, boost::system::error_code* pErrorCodeOut, std::size_t* pSizeOut);
00067
00068 boost::asio::io_service m_IoService;
00069 boost::asio::serial_port m_SerialPort;
00070 boost::asio::deadline_timer m_Timer;
00071 };
00072
00073 RmpUsb::RmpUsb(const std::string& rDevicePort)
00074 : m_pImpl(new Impl(rDevicePort))
00075 {}
00076
00077 RmpUsb::~RmpUsb()
00078 {}
00079
00080 bool RmpUsb::Send(uint16_t commandId, uint32_t value1, uint32_t value2)
00081 {
00082 Bytes message;
00083 ConvertCommandToBytes(commandId, value1, value2, message);
00084 AppendCrc16(message);
00085
00086 boost::system::error_code errorCode;
00087 size_t bytesSent = m_pImpl->Write(message, TIMEOUT, errorCode);
00088
00089 if (errorCode.value() != boost::system::errc::success)
00090 {
00091 SEGWAY_LOG(ERROR, "Fail to usb send: " << errorCode.message());
00092
00093 return false;
00094 }
00095
00096 if (bytesSent != message.size())
00097 {
00098 return false;
00099 }
00100
00101 return true;
00102 }
00103
00104 bool RmpUsb::Receive(Bytes& rData, size_t size)
00105 {
00106 rData.resize(size + CRC_FEEDBACK_SIZE);
00107
00108 boost::system::error_code errorCode;
00109 size_t bytesReceived = m_pImpl->Read(rData, TIMEOUT, errorCode);
00110
00111 if (errorCode.value() != boost::system::errc::success)
00112 {
00113 SEGWAY_LOG(DEBUG, "Fail to receive usb packet: " << errorCode.message());
00114
00115 return false;
00116 }
00117
00118 if (bytesReceived != (size + CRC_FEEDBACK_SIZE))
00119 {
00120 SEGWAY_LOG(DEBUG, "Received usb packet of unexpected size: " << bytesReceived << ", expected: " << size + CRC_FEEDBACK_SIZE);
00121
00122 return false;
00123 }
00124
00125 if (!IsCrcValid(rData, bytesReceived))
00126 {
00127 SEGWAY_LOG(ERROR, "CRC mismatched on usb receive.");
00128
00129 return false;
00130 }
00131
00132 rData.erase(rData.begin() + size, rData.end());
00133
00134 return true;
00135 }
00136
00137 RmpUsb::Impl::Impl(const std::string& rDevicePort)
00138 : m_IoService()
00139 , m_SerialPort(m_IoService)
00140 , m_Timer(m_IoService)
00141 {
00142 boost::system::error_code errorCode;
00143 m_SerialPort.open(rDevicePort, errorCode);
00144
00145 if (errorCode.value() != boost::system::errc::success)
00146 {
00147 std::stringstream stringStream;
00148 stringStream << "Unable to open serial port " << rDevicePort << ": " << errorCode.message();
00149
00150 throw std::runtime_error(stringStream.str());
00151 }
00152
00153 m_SerialPort.set_option(boost::asio::serial_port_base::baud_rate(BAUD_RATE));
00154 m_SerialPort.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
00155 m_SerialPort.set_option(boost::asio::serial_port_base::character_size(CHARACTER_SIZE));
00156 m_SerialPort.set_option(boost::asio::serial_port_base::flow_control(boost::asio::serial_port_base::flow_control::none));
00157 m_SerialPort.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
00158
00159 m_Timer.expires_at(boost::posix_time::pos_infin);
00160
00161 CheckDeadline();
00162 }
00163
00164 size_t RmpUsb::Impl::Write(const Bytes& rData, float timeout, boost::system::error_code& rErrorCode)
00165 {
00166 m_Timer.expires_from_now(boost::posix_time::milliseconds(timeout));
00167
00168 rErrorCode = boost::asio::error::would_block;
00169 size_t size = 0;
00170
00171 boost::asio::async_write(m_SerialPort, boost::asio::buffer(rData), boost::bind(&Impl::Handle, _1, _2, &rErrorCode, &size));
00172
00173 do
00174 {
00175 m_IoService.run_one();
00176 }
00177 while (rErrorCode == boost::asio::error::would_block);
00178
00179 return size;
00180 }
00181
00182 size_t RmpUsb::Impl::Read(Bytes& rData, float timeout, boost::system::error_code& rErrorCode)
00183 {
00184 m_Timer.expires_from_now(boost::posix_time::milliseconds(timeout));
00185
00186 rErrorCode = boost::asio::error::would_block;
00187 size_t size = 0;
00188
00189 boost::asio::async_read(m_SerialPort, boost::asio::buffer(rData), boost::bind(&Impl::Handle, _1, _2, &rErrorCode, &size));
00190
00191 do
00192 {
00193 m_IoService.run_one();
00194 }
00195 while (rErrorCode == boost::asio::error::would_block);
00196
00197 return size;
00198 }
00199
00200 void RmpUsb::Impl::CheckDeadline()
00201 {
00202 if (m_Timer.expires_at() <= boost::asio::deadline_timer::traits_type::now())
00203 {
00204 m_SerialPort.cancel();
00205
00206 m_Timer.expires_at(boost::posix_time::pos_infin);
00207 }
00208
00209 m_Timer.async_wait(boost::bind(&Impl::CheckDeadline, this));
00210 }
00211
00212 void RmpUsb::Impl::Handle(const boost::system::error_code& rErrorCodeIn, size_t sizeIn, boost::system::error_code* pErrorCodeOut, std::size_t* pSizeOut)
00213 {
00214 *pErrorCodeOut = rErrorCodeIn;
00215 *pSizeOut = sizeIn;
00216 }
00217
00218 }