AsioSerialDriver.h
Go to the documentation of this file.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 #ifndef __BOOST_ASIO_SERIAL_DRIVER_h__
00040 #define __BOOST_ASIO_SERIAL_DRIVER_h__
00041
00042 #include <boost/bind.hpp>
00043 #include <boost/asio.hpp>
00044 #include <boost/asio/serial_port.hpp>
00045 #include <deque>
00046 #include <iostream>
00047
00048 #include "case/Delegate.h"
00049 #include "devices/nic/serial/SerialFrameDelimiter.h"
00050 #include "util/CommandLineParameterGenerator.h"
00051 #include "util/ios.h"
00052
00053 #include "debug.h"
00054
00055 using namespace std;
00056 namespace device {
00057 namespace nic {
00058 namespace serial {
00059
00060 CLP2(ASIOOptions,
00061 "ASIO Serial Driver",
00062 "serial,s",
00063 "The device that is used and the baudrate in the form of device:baudrate"
00064 "Values:\n"
00065 " Device: \tdevice that has to be used\n"
00066 " Baudrate: \tlegal values are\n"
00067 " 0 = 300 bps\n"
00068 " 1 = 600 bps\n"
00069 " 2 = 1200 bps\n"
00070 " 3 = 2400 bps\n"
00071 " 4 = 4800 bps\n"
00072 " 5 = 9600 bps\n"
00073 " 6 = 19200 bps\n"
00074 " 7 = 38400 bps\n"
00075 " 8 = 57600 bps\n"
00076 " 9 = 115200 bps\n"
00077 " Packetsize: \tmax size of a packet\n"
00078 "(e.g. /dev/ttyS0:6: (default))",
00079 std::string, device, "/dev/ttyS0",
00080 int, baudrate, 6);
00081
00090 template <
00091 uint8_t PL = 255,
00092 class SFD = struct SerialFrameDelimiter
00093 >
00094 class AsioSerialDriver : boost::noncopyable {
00095 public:
00097 typedef AsioSerialDriver< PL, SFD > type;
00099 struct cfgInfo {
00100 enum {
00101 payload = PL
00102 };
00103 };
00105 typedef struct __attribute__((packed)) {
00106 uint8_t size;
00107 uint8_t payload[cfgInfo::payload];
00108 } mob_t;
00109
00110 AsioSerialDriver() :
00111 _io_service(famouso::util::ios::instance()),
00112 _serialPort(_io_service) {
00113 }
00114 ~AsioSerialDriver() {
00115 _serialPort.close();
00116 }
00117
00121 void close(const boost::system::error_code& error) {
00122
00123
00124 if (error == boost::asio::error::operation_aborted)
00125 return;
00126 if (error) {
00127 ::logging::log::emit< ::logging::Error>()
00128 << error.message().c_str()
00129 << ::logging::log::endl;
00130 }
00131 _serialPort.close();
00132 }
00133
00139 void doneRead(const boost::system::error_code& error, std::size_t size) {
00140 char aChar;
00141
00142 if (!error) {
00143 std::istream is(&trxBuffer);
00144 while (size--) {
00145 driverState = ( _rmobj.size > cfgInfo::payload ) ? invalid : driverState;
00146 is.get( aChar );
00147 switch ( aChar ) {
00148 case (SFD::sofr):
00149 driverState = ( driverState == invalid ) ? regular : invalid;
00150 _rmobj.size = 0;
00151 break;
00152 case (SFD::eofr):
00153 driverState = ( driverState == regular ) ? valid : invalid;
00154 if ( (driverState == valid) && this->onReceive) this->onReceive();
00155 break;
00156 case (SFD::esc):
00157 driverState = ( driverState == regular ) ? stuff : invalid;
00158 break;
00159 default:
00160 if ( driverState == regular || driverState == stuff ) {
00161 aChar = ( driverState == stuff && SFD::escmod != 0) ? (aChar ^ SFD::escmod) : aChar;
00162 _rmobj.payload[_rmobj.size++] = (uint8_t)aChar;
00163 driverState = regular;
00164 } else driverState = invalid;
00165 break;
00166 }
00167 }
00168 boost::asio::async_read_until(
00169 _serialPort, trxBuffer, SFD::eofr,
00170 boost::bind(&type::doneRead, this,
00171 boost::asio::placeholders::error,
00172 boost::asio::placeholders::bytes_transferred));
00173 } else close(error);
00174 }
00175
00181 void doneWrite(const boost::system::error_code& error, std::size_t size) {
00182 if ( !error ) {
00183 trxBuffer.consume(size);
00184 if ( this->onReady ) this->onReady();
00185 } else close(error);
00186 }
00187
00195 void init() {
00196 TRACE_FUNCTION;
00197
00198 CLP::config::ASIOOptions::Parameter param;
00199 CLP::config::ASIOOptions::instance().getParameter(param);
00200 if ( (param.baudrate < 0) || (param.baudrate > 9) ) {
00201 ::logging::log::emit< ::logging::Error>()
00202 << "Error: parameter baudrate out of Range"
00203 << ::logging::log::endl;
00204 exit(0);
00205 }
00206
00207 famouso::util::impl::start_ios();
00208
00209 _serialPort.open( param.device.c_str() );
00210 if ( !_serialPort.is_open() ) {
00211 ::logging::log::emit< ::logging::Error>()
00212 << "can't open serial device "
00213 << param.device.c_str() << ::logging::log::endl;
00214 exit(0);
00215 }
00216
00217 _serialPort.set_option(
00218 boost::asio::serial_port_base::character_size( 8 ) );
00219 _serialPort.set_option(
00220 boost::asio::serial_port_base::flow_control(
00221 boost::asio::serial_port_base::flow_control::none ) );
00222 uint16_t baudrate = (0x01 << param.baudrate) * 300;
00223 _serialPort.set_option(
00224 boost::asio::serial_port_base::baud_rate( baudrate ) );
00225 _serialPort.set_option(
00226 boost::asio::serial_port_base::parity(
00227 boost::asio::serial_port_base::parity::none ) );
00228 _serialPort.set_option(
00229 boost::asio::serial_port_base::stop_bits(
00230 boost::asio::serial_port_base::stop_bits::one) );
00231
00232 boost::asio::async_read_until(
00233 _serialPort, trxBuffer, SFD::eofr,
00234 boost::bind(&type::doneRead, this,
00235 boost::asio::placeholders::error,
00236 boost::asio::placeholders::bytes_transferred));
00237 }
00238
00242 void recv(mob_t& msg) {
00243 TRACE_FUNCTION;
00244
00245 msg.size = 0;
00246 while ( driverState != valid );
00247
00248 for (;msg.size < _rmobj.size; msg.size++) {
00249 msg.payload[msg.size] = _rmobj.payload[msg.size];
00250 }
00251 driverState = invalid;
00252 }
00253
00257 void send(const mob_t& message) {
00258 TRACE_FUNCTION;
00259
00260 std::ostream os(&trxBuffer);
00261 uint8_t aByte = 0;
00262
00263
00264 os.put( (uint8_t)SFD::sofr );
00265 for (uint16_t index = 0;index < message.size;index++) {
00266 aByte = message.payload[index];
00267 if ( aByte == SFD::esc ||
00268 aByte == SFD::eofr ||
00269 aByte == SFD::sofr ) {
00270 os.put( (uint8_t)SFD::esc );
00271 os.put( ((SFD::escmod != 0) ? aByte ^ SFD::escmod : aByte));
00272 } else {
00273 os.put( aByte );
00274 }
00275 }
00276 os.put( (uint8_t)SFD::eofr );
00277
00278 boost::asio::async_write(
00279 _serialPort,
00280 trxBuffer,
00281 boost::bind(&type::doneWrite, this,
00282 boost::asio::placeholders::error,
00283 boost::asio::placeholders::bytes_transferred));
00284 }
00285
00287 famouso::util::Delegate<> onReceive;
00288
00294 famouso::util::Delegate<> onReady;
00295 private:
00296 boost::asio::io_service& _io_service;
00297 boost::asio::serial_port _serialPort;
00298 boost::asio::streambuf trxBuffer;
00299 enum { valid, invalid, regular, stuff } driverState;
00300 mob_t _rmobj;
00301 };
00302 }
00303 }
00304 }
00305
00306 #endif //__BOOST_ASIO_SERIAL_DRIVER_h__