Developing a Device Class
[Developer Manual]

For each Rulbus module a class is defined to encapsulate the module's settings and behavior.

The class declaration is placed in a .h file and the implementation is placed in a .cpp file. The names of the files follow the pattern rbyydd_name. For example: rdcl_rb8510_dac12.h and rdcl_rb8510_dac12.cpp

These sourcefiles are located in the subdirectory {project-root}/rulbus-rdcl/src/.

Please take a look at the creation of the RB8510_Dac12 driver. The doxygen documentation is omitted for clarity, see section Rulbus Device Class Template of the Style Guide for that.

Class Declaration

First we declare the class for the DAC and add inline implementation for the simplest accessor methods.

#include "rdcl/RulbusDevice.h"  // classes RulbusDevice, RulbusInterface, RulbusError

namespace Rulbus
{
   DECLARE_CLASS( RB8510_Dac12 );               // the 12-bit DAC class type

   class RB8510_Dac12 : public RulbusDevice
   {
   public:                              // public methods
      typedef Int  Value;

      RB8510_Dac12(
         NameCref aName,
         Addr     aAddr        = DEF_ADDR,
         Rack     aRack        = DEF_RACK,
         bool     aBipolarFlag = DEF_BIP,
         Real     aVoltPerBit  = DEF_VPB );

      ~RB8510_Dac12();

      Volt    voltage() const;
      Value   value() const;

      bool    isBipolar() const;
      float   voltperbit() const;

      void    setVoltage ( Volt  aVoltage );
      void    setValue   ( Value aValue   );

   protected:                                   // protected methods
      RB8510_Dac12();
      RB8510_Dac12( RB8510_Dac12Cref rhs );
      RB8510_Dac12Ref operator= ( RB8510_Dac12Cref rhs );

   public:                                      // public data
      static const Addr  DEF_ADDR = 0xD0;
      static const Rack  DEF_RACK = 0;
      static const bool  DEF_BIP  = true;
      static const Real  DEF_VPB  /* = 5e-3 */;

      static const Value LIM_MINVAL = 0x0000;
      static const Value LIM_MAXVAL = 0x0FFF;
      static const Value LIM_BIPVAL = 0x0800;

   private:                                     // private data
      Value theRegister;
      bool  theBipolarFlag;
      Real  theVoltPerBit;

      static const int   OFF_MSB = 0;
      static const int   OFF_LSB = 1;

      static const int ADR_WIDTH = OFF_LSB + 1;
   };

   /*
 the current DAC-register value.
    */

   inline RB8510_Dac12::Value RB8510_Dac12::value() const
   {
      return theRegister;
   }

   /*
 the current DAC output voltage.
    */

   inline bool RB8510_Dac12::isBipolar() const
   {
      return theBipolarFlag;
   }

   /*
 the DAC's output sensitivity configuration.
    */

   inline Real RB8510_Dac12::voltperbit() const
   {
      return theVoltPerBit;
   }

} // namespace Rulbus

The class derives from class RulbusDevice and it contains a constructor to create an object of this class in a defined state, it contains selector methods and modifier methods and it contains state information.

Candidates for constructor parameters are characteristics fixed at production-time, like the Rulbus address and, for the DAC, the ouput polarity (bipolar / unipolar) and sensitivity (volt-per-bit, or vpb).

Candidates for selector and modifier methods are the modifiable characteristics of the Rulbus module, like the output voltage of a DAC.

The datamembers of the class hold the state information for the Rulbus module that it cannot memorize itself. Most Rulbus modules cannot be queried for their settings at all.

Further the class holds constant values we need for the class methods, like register offsets and minimum and maximum values. Constants are declared static const type name.

The constructor above is defined inline. It saves the fixed characteristics polarity and sensitivity to the respective datamembers, delegates the name and address information to the constructor of the RulbusDevice base class and finally sets the DAC ouput voltage to zero volt.

Class Implementation

Finally, we define the contents of the non-inline method bodies in the .cpp file, contained in the Rulbus namespace.

namespace Rulbus
{
   // the implementation goes here...
}

Data that requires a location or requires initialization in the .cpp file.

const Real RB8510_Dac12::DEF_VPB = 5e-3f;      ///< default bipolar, -10.24..+10.23V

The constructor.

RB8510_Dac12::RB8510_Dac12(
   NameCref aName,
   Addr     aAddr        /* = DEF_ADDR */,
   Rack     aRack        /* = DEF_RACK */,
   bool     aBipolarFlag /* = DEF_BIP */,
   Real     aVoltPerBit  /* = DEF_VPB */)
   :
   RulbusDevice  ( aName, aAddr, aRack ),
   theBipolarFlag( aBipolarFlag ),
   theVoltPerBit ( aVoltPerBit  )
{
   setVoltage( 0 );
}

The destructor.

RB8510_Dac12::~RB8510_Dac12()
{
   ; // do nothing
}

Method voltage() returns the saved DAC-register value transformed into the voltage.

Volt RB8510_Dac12::voltage() const
{
   Value code = value();

   if ( isBipolar() )
      code -= LIM_BIPVAL;

   return voltperbit() * code;
}

Method setValue() first checks if the value specified is valid, saves the value in the datamember theRegister and updates the DAC-register. If the value specified is invalid, setValue() throws a RulbusRangeError.

void RB8510_Dac12::setValue( Value aValue )
{
   if ( aValue < LIM_MINVAL || aValue > LIM_MAXVAL )
      throw RulbusRangeError( name(), "value", aValue, LIM_MINVAL, LIM_MAXVAL );

   theRegister = aValue;

   putByte( OFF_MSB, aValue / 256 );
   putByte( OFF_LSB, aValue % 256 );
}

Method setVoltage() transforms the specified voltage into a DAC-code and delegates the remaining work to method setValue(). If the voltage specified is not within the capablilities if the DAC, setValue() will throw a RulbusRangeError. setVoltage() catches this error and transforms it into a new RulbusRangeError now specifying the range error in terms of voltage.

void RB8510_Dac12::setVoltage( Volt aVoltage )
{
   Value code = ( aVoltage < 0 ? -0.5 : +0.5) + aVoltage / voltperbit();

   if ( isBipolar() )
      code += LIM_BIPVAL;

   try
   {
      setValue( code );
   }
   catch ( RulbusRangeErrorCref e )
   {
      Volt offset = isBipolar() ? -LIM_BIPVAL * voltperbit(): 0;

      throw RulbusRangeError( name(), "voltage", aVoltage,
         offset + voltperbit() * LIM_MINVAL, offset + voltperbit() * LIM_MAXVAL );
   }

   ensure( std::fabs( voltage() - aVoltage ) < voltperbit() / 2 + std::numeric_limits<Volt>::epsilon() );
}


Generated on Tue Oct 12 14:12:03 2004 for Rulbus Device Class Library for Microsoft Windows by doxygen 1.3.4