Domande di interfaccia per l'utilizzo del modello di comando e dell'iniezione delle dipendenze insieme

2

Ho molti progetti che hanno essenzialmente lo stesso requisito di alto livello: testare tutto l'hardware su un dispositivo. Ogni dispositivo può avere un protocollo di comunicazione diverso, richiede diverse apparecchiature di test per esercitare il dispositivo, ecc. Quindi, ad un livello elevato un test è essenzialmente il seguente:

  1. ottieni gli handle per testare l'attrezzatura
  2. applica lo stimolo al dispositivo
  3. misura / rileva / registra qualcosa misurabile
  4. rimuovi lo stimolo
  5. archivia i risultati
  6. gestisce gli errori

Ho quindi creato una classe di interfaccia (CTestEquipment) poiché ogni pezzo di apparecchiatura di prova può essere una classe concreta con un'implementazione unica. Anche il dispositivo in prova può essere considerato un pezzo di apparecchiatura di prova. Uso l'iniezione di dipendenza per il conducente dell'attrezzatura di prova. Ciò consente di cambiare facilmente da un guidatore all'altro e di tenere un po 'disaccoppiato il conducente e l'attrezzatura. Ad esempio, un alimentatore potrebbe utilizzare un driver GPIB, un driver VISA o comandi seriali grezzi. Ogni progetto può scegliere quale è applicabile e modificare una linea (l'istanza del driver).

Successivamente, ho creato classi per implementare il pattern Command per l'apparecchiatura / dispositivo di test. Pertanto, CTestEquipment eredita da CCmdReceiver. Una classe di comando concreta chiama il metodo execute che tramite il ricevitore chiama i metodi tx / rx dell'apparecchiatura di test. Questi metodi chiamano il driver sottostante.

Domande / Problemi: Come estrarre i dati ricevuti dal comando? In questo momento eseguire non ha argomenti e non restituisce nulla. Un comando concreto può solo trasmettere, solo ricevere, o fare entrambe le cose in modo che l'interfaccia di esecuzione debba restituire un valore anche quando non ci sono dati ricevuti o in qualche altro modo in cui ho bisogno di potervi accedere. CSetSerialNumber non ha dati ricevuti. CGetMode fa.

Poiché il comando chiama tx / rx che alla fine chiama tx / rx del driver, come posso impacchettare i dati su quelle chiamate, poiché ciascun driver potrebbe prendere qualcosa di diverso? Ho preso in considerazione un'interfaccia CPacket e varie implementazioni concrete, ma come posso assicurarmi che il passaggio di una classe concreta che non corrisponde al driver venga intercettata?

//--------------------------------------------------------------------------------------
// CCommand
//      Abstract interface that defines the execute method
//--------------------------------------------------------------------------------------
class CCommand
{
protected:
CCmdReceiver *      _rcvr_p;            // receiver interface

// Default Constructor
CCommand()
{}

public:
// Constructor
CCommand
    (
    CCmdReceiver *  r               // receiver interface
    ) :
   _rcvr_p      ( r )
{}

// Destructor
virtual ~CCommand()
{}

// Method to Execute the Command
virtual void execute() = 0;
};

//--------------------------------------------------------------------------------------
// CCmdReceiver
//      Abstract interface that defines the command action
//--------------------------------------------------------------------------------------
class CCmdReceiver
{
public:
virtual void flush() = 0;

virtual void rx( std::vector< unsigned char > & v ) = 0;

//virtual void tx( std::string const & s ) = 0;
virtual void tx( CPacket * p ) = 0;
};

/*------------------------------------------------------------------------------
Test equipment driver abstract base class
------------------------------------------------------------------------------*/
class CDriver
{
public:
/*--------------------------------------------------------------------------
Constructor
--------------------------------------------------------------------------*/
CDriver() :
    _is_open            ( false )
{}

/*--------------------------------------------------------------------------
Destructor
--------------------------------------------------------------------------*/
virtual ~CDriver()
{}

//protected:
/*--------------------------------------------------------------------------
Close the Driver
    Must be implemented in a derived class
--------------------------------------------------------------------------*/
virtual void close() = 0;

/*--------------------------------------------------------------------------
Get the Received Data
--------------------------------------------------------------------------*/
template< typename tVal >
tVal getRxData();

/*--------------------------------------------------------------------------
Determine if the Driver is Open
--------------------------------------------------------------------------*/
virtual bool isOpen()
{
return( _is_open );
}

/*--------------------------------------------------------------------------
Open the Driver
    Must be implemented in a derived class
--------------------------------------------------------------------------*/
virtual void open() = 0;

/*--------------------------------------------------------------------------
Receive Data
--------------------------------------------------------------------------*/
virtual void rx()
{}

/*--------------------------------------------------------------------------
Set Open/Closed Flag State
--------------------------------------------------------------------------*/
inline void setOpenState
    (
    bool const & open = true
    )
{
_is_open = open;
}

/*--------------------------------------------------------------------------
Transmit Data
--------------------------------------------------------------------------*/
virtual void tx
    (
    std::string const & cmd         // command to transmit
    )
{}

private:
bool    _is_open;           // flag to indicate if protocol is open
};

//--------------------------------------------------------------------------------------
// Abstract Test Equipment Class
//      Utilizes constructor DI for device driver
//      Utilizes RAII for open/close
//--------------------------------------------------------------------------------------
class CTestEquipment : public CCmdReceiver
{
public:
/// Constructor
CTestEquipment
    (
    boost::shared_ptr< CDriver > const &
                drvr        // device driver
    ) :
    _drvr           ( drvr ),
    _init_cnt           ( 0 )
{
_drvr->open();
incInitCnt();
}

/// Destructor
virtual ~CTestEquipment()
{
if( isInitialized() )
     {
     _drvr->close();
     }
}

/// Function to Access the Equipment's Driver
inline boost::shared_ptr< CDriver > const & accessDriver() const
{
return( _drvr );
}   // accessDriver()

/// Decrement the Initialization Count
inline void decInitCnt()
{
--_init_cnt;
}   // decInitCnt()

/// Get the Initialization Count
inline int getInitCnt() const
{
return( _init_cnt );
}   // getInitCnt()

/// Increment the Initialization Count
inline void incInitCnt()
{
++_init_cnt;
}   // incInitCnt()

/// Check if Initialization has Occurred
inline bool isInitialized() const
{
return( _init_cnt >= 1 );
}   // isInitialized()

/// Determine if the Driver is Open
inline bool isOpen() const
{
return( _drvr->isOpen() );
}   // isOpen() 

 protected:
/// Reset the Equipment
virtual void reset()
{
//_drvr->reset();
}

/// Function to Receive Data from the Equipment
inline void rx()
{
_drvr->rx();
}

/// Function to Set the Device to a Default State
virtual void setToDflts()
{}

/// Function to Transmit a Command to the Equipment
inline void tx( std::string const & cmd )
{
_drvr->tx( cmd );
}

/// Function to Transmit a Command, Receive the Response, and Return the Parsed    Value
template< typename tVal >
tVal txRx
    (
    std::string const & cmd         // command to transmit
        )
{
_drvr->tx( cmd );
_drvr->rx();

return( _drvr->getRxData< tVal >() );
}

protected:
boost::shared_ptr< CDriver > const &
        _drvr;              // device driver
int     _init_cnt;          // initialization count
};

class CGetMode : public CCommand
{
public:
CGetMode
    (
    CCmdReceiver *  rcvr            // command receiver
    );

void execute()
    {
    // G: what type is cmd?
    // G: what type is buffer?
    // G: how do we access buffer?
    _rcvr_p->flush();
    _rcvr_p->tx( cmd );
    _rcvr_p->rx( buffer );
    }
 };

//--------------------------------------------------------------------------------------
// CSetSerialNumber
//     Extends command interface. Implements the execute method and invokes it on a receiver.
//--------------------------------------------------------------------------------------
class CSetSerialNumber : public CCommand
{
public:
// Constructor
CSetSerialNumber
    (
    CCmdReceiver *  rcvr                // command receiver
    );

void execute()
    {
    // G: what type is cmd?
    _rcvr_p->tx( cmd );
    }
};
    
posta Grasshopper 19.03.2014 - 23:33
fonte

1 risposta

1

È necessario un protocollo di trasferimento dati. Può essere semplice come una stringa con valori separati da virgole o complessi come alcuni XML supportati da uno schema. Qualunque cosa tu decida, il ricevitore dovrà essere abbastanza intelligente da decodificarlo.

Ad esempio, uno dei tuoi comandi potrebbe recuperare un'intestazione separata da virgole:

TIME, ALTITUDE, TEMPERATURE, AIRSPEED, WHATEVER

Questo ti dice non solo il nome di ciascun segnale, ma quanti segnali ci sono. È possibile utilizzare queste informazioni per configurare il decoder dal lato del ricevitore.

Potresti anche utilizzare qualcosa come Buffer del protocollo .

    
risposta data 20.03.2014 - 00:02
fonte

Leggi altre domande sui tag