⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iomodule.cpp

📁 美国COPLEY驱动器,程序开发工具之一.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/************************************************************/
/*                                                          */
/*  Copley Motion Libraries                                 */
/*                                                          */
/*  Author: Stephen Glow                                    */
/*                                                          */
/*  Copyright (c) 2002-2005 Copley Controls Corp.           */
/*                          http://www.copleycontrols.com   */
/*                                                          */
/************************************************************/

/** \file
  I/O module object support.  This file holds the code used to implement
  a standard DS401 I/O module.
  */

#include "CML.h"

CML_NAMESPACE_USE();

// I/O module specific error objects
CML_NEW_ERROR( IOError, BadID,      "The passed digital I/O pin ID number is invalid" );
CML_NEW_ERROR( IOError, BadIOCount, "The number of passed I/O ID blocks is invalid" );

/***************************************************************************/
/**
  Default constructor for an I/O module.  
  Any object created using this constructor must be initialized by a call 
  to IOModule::Init before it is used.
  */
/***************************************************************************/
IOModule::IOModule( void )
{
   // This delay is a work-around for Beckhoff I/O modules which
   // don't conform to the CANopen spec.
   stateChangeDelay = 10;
}

/***************************************************************************/
/**
  Construct an IOModule object and initialize it using default settings.
  @param co The CANopen network object that this module is associated with.
  @param nodeID The node ID of the module on the network.
  */
/***************************************************************************/
IOModule::IOModule( CanOpen &co, int16 nodeID )
{
   Init( co, nodeID );
}

/***************************************************************************/
/**
  Construct an IOModule object and initialize it using custom settings.
  @param co The CANopen network object that this module is associated with.
  @param nodeID The node ID of the module on the network.
  @param settings The settings to use when configuring the module
  */
/***************************************************************************/
IOModule::IOModule( CanOpen &co, int16 nodeID, IOModuleSettings &settings )
{
   Init( co, nodeID, settings );
}

/***************************************************************************/
/**
  Virtual destructor for the IOModule object.
  */
/***************************************************************************/
IOModule::~IOModule()
{
}

/***************************************************************************/
/**
  Initialize an I/O module using default settings.  This function associates the 
  object with the CANopen network it will be used on.

  @param co The CANopen network object that this module is associated with.
  @param nodeID The node ID of the module on the network.
  @return A pointer to an error object, or NULL on success
  */
/***************************************************************************/
const Error *IOModule::Init( CanOpen &co, int16 nodeID )
{
   IOModuleSettings settings;
   return Init( co, nodeID, settings );
}

/***************************************************************************/
/**
  Initialize an I/O module using custom settings.  This function associates the 
  object with the CANopen network it will be used on.

  @param co The CANopen network object that this module is associated with.
  @param nodeID The node ID of the module on the network.
  @param settings The settings to use when configuring the module
  @return A pointer to an error object, or NULL on success
  */
/***************************************************************************/
const Error *IOModule::Init( CanOpen &co, int16 nodeID, IOModuleSettings &settings )
{
   // Init the base class
   const Error *err = Node::Init( co, nodeID );
   if( err ) return err;

   // Make sure we're in pre-op state.  This allows us to map
   // the PDO objects.
   err = PreOpNode();
   if( err ) return err;

   // Check to see if analog & digital interrupts are enabled.
   // On error, just assume they are
   if( DinGetIntEna( dinIntEna ) ) dinIntEna = true;
   if( AinGetIntEna( ainIntEna ) ) ainIntEna = true;

#ifdef CML_ENABLE_IOMODULE_PDOS
   // Check the number of 8-bit digital output blocks.  If this is
   // more then zero then I'll map them (up to 8) to the first 
   // receive PDO.  Note that I don't check errors here.  If this
   // fails the count will come back as zero.
   uint8 ct;
   Dout8GetCt( ct );

   if( ct && settings.useStandardDoutPDO )
   {
      if( ct > 8 ) ct = 8;

      uint8 ids[8];
      for( int i=0; i<ct; i++ ) ids[i] = i;

      err = doutPDO.Init( this, GetRpdoCobID(0), ct, ids );

      if( !err ) err = PdoSet( 0, doutPDO );
      if( err ) return err;
   }

   // Map up to 12 16-bit analog outputs to PDOs.  These are the
   // standard analog output PDOs defined by the spec.
   if( settings.useStandardAoutPDO )
   {
      Aout16GetCt( ct );

      for( int n=0; n<3 && ct>0; n++ )
      {
	 uint8 map = ct;
	 if( map > 4 ) map = 4;
	 ct -= map;

	 uint8 ids[4];
	 for( int i=0; i<map; i++ ) ids[i] = 4*n+i;

	 err = aoutPDO[n].Init( this, GetRpdoCobID(n+1), map, ids );

	 if( !err ) err = PdoSet( n+1, aoutPDO[n] );
	 if( err ) return err;
      }
   }

   // Check the number of 8-bit digital input blocks.  If this is
   // more then zero then I'll map them (up to 8) to the first 
   // transmit PDO.  Note that I don't check errors here.  If this
   // fails the count will come back as zero.
   Din8GetCt( ct );
   if( ct && settings.useStandardDinPDO )
   {
      if( ct > 8 ) ct = 8;

      uint8 ids[8];
      for( int i=0; i<ct; i++ ) ids[i] = i;

      err = dinPDO.Init( this, GetTpdoCobID(0), ct, ids, IOEVENT_DIN_PDO0 );

      if( !err ) err = PdoSet( 0, dinPDO );
      if( err ) return err;
   }

   // Map up to 12 16-bit analog inputs to PDOs.  These are the
   // standard analog input PDOs defined by the spec.
   if( settings.useStandardAinPDO )
   {
      Ain16GetCt( ct );

      for( int n=0; n<3 && ct>0; n++ )
      {
	 uint8 map = ct;
	 if( map > 4 ) map = 4;
	 ct -= map;

	 uint8 ids[4];
	 for( int i=0; i<map; i++ ) ids[i] = 4*n+i;

	 err = ainPDO[n].Init( this, GetTpdoCobID(n+1), map, ids, 
	                       (IOMODULE_EVENTS)(IOEVENT_AIN_PDO0<<n) );

	 if( !err ) err = PdoSet( n+1, ainPDO[n] );
	 if( err ) return err;
      }
   }
#endif

   // Setup heartbeat or node guarding
   if( settings.heartbeatPeriod )
      err = StartHeartbeat( settings.heartbeatPeriod, settings.heartbeatTimeout );

   else if( settings.guardTime && settings.lifeFactor )
      err = StartNodeGuard( settings.guardTime, settings.lifeFactor );

   else
      err = StopGuarding();

   if( err ) return err;

   // Put the node into operational state 
   return StartNode();
}

/***************************************************************************/
/**
  Write an individual digital output.

  The output may be written either by SDO or by PDO.  The PDO method 
  is faster since it only requires a single message to be sent.  SDO 
  transfers additionally require a response from the module.  

  If a PDO transfer is requested, but is not possible because the module is
  not in an operational state, or because the output isn't mapped to
  the PDO, then an SDO transfer will be used.

  @param id Identifies which output to write.
  @param value The new value of the output line.
  @param viaSDO If true, the outputs will be written using SDO messages.
  If false (default), then a PDO will be used if possible.
  @return A pointer to an error object, or NULL on success
  */
/***************************************************************************/
const Error *IOModule::DoutWrite( uint16 id, bool value, bool viaSDO )
{
#ifdef CML_ENABLE_IOMODULE_PDOS
   // Update the bit value in the PDO to keep my local data current.
   // If this fails, then the bit isn't mapped and I'll have to use
   // an SDO to update it.
   if( !doutPDO.UpdateBit( id, value ) )
      viaSDO = true;

   // Output this using a PDO if requested and possible
   if( (!viaSDO) && (GetState() == NODESTATE_OPERATIONAL) )
      return doutPDO.Transmit();

   else
#endif
      return BitDnld( IOOBJID_DOUT_1_VALUE, id, value );
}

/***************************************************************************/
/**
  Write a group of 8 digital outputs.

  The outputs may be written either by SDO or by PDO.  The PDO method 
  is faster since it only requires a single message to be sent.  SDO 
  transfers additionally require a response from the module.  

  If a PDO transfer is requested, but is not possible because the module is
  not in an operational state, or because the output block isn't mapped to
  the PDO, then an SDO transfer will be used.

  @param id Identifies which group of outputs to write.   
  @param value The new value of the output lines.         
  @param viaSDO If true, the outputs will be written using SDO messages.
  If false (default), then a PDO will be used if possible.
  @return A pointer to an error object, or NULL on success
  */
/***************************************************************************/
const Error *IOModule::Dout8Write( uint8 id, uint8 value, bool viaSDO )
{
#ifdef CML_ENABLE_IOMODULE_PDOS
   // Update the PDO even if we are using an SDO.  This keeps
   // my PDO data up to date.
   if( !doutPDO.Update( id, value ) )
      viaSDO = true;

   // Output this using a PDO if requested and possible
   if( (!viaSDO) && (GetState() == NODESTATE_OPERATIONAL) )
      return doutPDO.Transmit();

   else
#endif
      return sdo.Dnld8( IOOBJID_DOUT_8_VALUE, id+1, value );
}

/***************************************************************************/
/**
  Write a group of 16 digital outputs.

  The outputs may be written either by SDO or by PDO.  The PDO method 
  is faster since it only requires a single message to be sent.  SDO 
  transfers additionally require a response from the module.  

  If a PDO transfer is requested, but is not possible because the module is
  not in an operational state, or because the output block isn't mapped to
  the PDO, then an SDO transfer will be used.

  @param id Identifies which group of outputs to write.
  @param value The new value of the output lines.
  @param viaSDO If true, the outputs will be written using SDO messages.
  If false (default), then a PDO will be used if possible.
  @return A pointer to an error object, or NULL on success
  */
/***************************************************************************/
const Error *IOModule::Dout16Write( uint8 id, uint16 value, bool viaSDO )
{
#ifdef CML_ENABLE_IOMODULE_PDOS
   if( id >= 127 ) 
      viaSDO = true;

   else if( !doutPDO.Update( 2*id, (uint8)value ) )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -