I've to implement a protocol communication with a device throw serial port. The protocol is binary based where we have an header that containt the kind and the length of the packet, an optional body and a checksum.
I'm using C++11 with Visual C++ 2012 with the v110_xp toolset.
My first attempt to implement it is using the following class:
PacketOutA
, PacketOutB
, PacketOutC
are all classes with a common interface, they have just two method: begin()
and end()
to access internal data;
I have an interface for response packet IPacketIn
, a derived class PacketIn
the implement common staff and the derivates PacketInA
, PacketInB
and so on.
The class Communication
is used to allow me to send and recieve data to the communication port.
The ReaderAndValidator
class allow me to get validate the recieved packet and get the body.
Dispatcher< T >
is used to get the corrisponding input packet from the requestç
PacketInA doPacketA()
{
PacketA packetA;
Dispatcher< PacketA > disp( communication );
PacketInA result = controller.send( packetA );
return result; // RVO
}
Let's look the snippet of the code:
class Communication {
public:
Communication ();
template < typename Iterator >
void send( Iterator first, Iterator last ) const
{
// send from first to last to
}
template< typename Iterator >
std::vector< char > read( Iterator first, Iterator last ) const
{
// read from first to last to
}
private:
// internal stuff
};
class ReaderAndValidator{
public:
ReaderAndValidator( const Communication& comm )
: mComm( comm )
{
}
std::vector< char > read()
{
// read data
return mComm.read( /* params */ );
}
private:
const Communication& mComm;
}
template < typename PacketOut >
class Dispatcher{
Dispatcher()
{
static_assert( false, "unable to instantiate Controller" );
}
};
template <>
class Dispatcher< PacketOutA > {
public:
Dispatcher( const Communication& comm )
: mComm( comm )
{
}
PacketInA send( const PacketOutA & packet ) const
{
mComm.send( std::begin( packet ), std::end( packet ) );
ReaderAndValidator readAndValidate( mComm );
auto body = readAndValidate.read();
// RVO
PacketInA result( std::begin( body ), std::end( body ) );
return result;
}
private:
const Communication& mComm;
};
// same thing for Dispatcher< PacketOutB >, Dispatcher< PacketOutC > and so on
The class Device
abstract the operation that I can do on my device
class Device : private boost::noncopyable {
public:
Device ()
{
// init communication
}
void doPacketOutA( int param )
{
PacketOutA packet( param );
recieve( packet );
}
PacketInB doPacketB()
{
PacketOutB packet();
return recieve( packet );
}
private:
template < typename PacketOutKind >
auto recieve( const PacketOutKind& p ) -> decltype( Dispatcher< PacketOutKind >::send( p ) )
{
Dispatcher< PacketOutKind > disp( mCommunication );
return controller.send( p );
}
private:
Communication mCommunication;
};
But I have a problem with the recieved method: how can I deduce the return type in this situation?
Is this design a good choice? Are better way to do the same thing?