This page describes in detail how to integrate foreign components
with modeled controllers. An architectural diagram of the system shows
the components and all the connections between them. TismTool generates
source code for instantiating the components and establishing all
connections between any pair of components. It expects from a foreign
component the same set of interfaces that are also generated/realised
for the modeled components.
The examples below show for all 4 programming languages how foreign
components could be implemented. These examples are based on the Foreign demo. The Foreign
controller has a (foreign) client component called User and a (foreign) server
component called Driver.
The pattern followed is that a foreign component contains a behaviour
class, that is accessed via a port. So, the 3 involved classes per
foreign component are:
This class implements the 2 functions (GetProvidedInterface() and SetRequiredInterface()) for
connecting to the controller. It provides its own port TsmPI__Port that has been created
in the constructor. And it receives the port named Port from the controller.
Furthermore, the (overridden) TsmRun()
function is responsible for all the activity of triggering the
controller and waiting for the response. Finally, the provided
interface (ICbCtlrServer) has
been implemented with the callback function CbStarted().
Note the remark "Do NOT
fill in Port.Source !!" . In the mocks (where this code
can be copied from) the Source
field is filled in on behalf of logging. Filling it here would corrupt
the logging.
public class UserClass : TsmClass, ICbCtlrServer
{
private MyTsmIPort_ICbCtlrServer TsmPI__Port;
private TsmIPort_ICtlrServer Port;
private int iRv;
private bool bCallback = false;
public UserClass( TsmBase oParent, string sInstanceName )
{
TsmPI__Port = new MyTsmIPort_ICbCtlrServer( this );
}
public override TsmInterfacePort GetProvidedInterface( string sPortName )
{
switch( sPortName )
{
case "UserPort":
return TsmPI__Port;
default :
break;
}
string s = "No port '" + sPortName + "' @ UserClass";
throw new TsmException( s );
}
public override void SetRequiredInterface( string sPortName, TsmInterfacePort oProvidedInterface )
{
switch( sPortName )
{
case "UserPort":
Port = (TsmIPort_ICtlrServer) oProvidedInterface;
// Do NOT fill in Port.Source !!
return;
default :
break;
}
string s = "No port '" + sPortName + "' @ UserClass";
throw new TsmException( s );
}
public override void TsmRun( object oObject )
{
iRv = Port.Start(true);
// Wait for response from callback function.
// Use global variable and non-busy polling for synchronisation.
while ( !bCallback )
{
Thread.Sleep( 100 );
}
// Grant time to CbThread to finish its callback activity.
Thread.Sleep( 1000 );
}
// ( UserClientPsm >> Starting ) => ( UserClientPsm >> Idle )
public void CbStarted( float fCbStart )
{
Tsm.Log( "CbStarted" );
bCallback = true;
}
}
This class of the foreign component instantiates the UserClass in its descriptor. It forwards the 2 connecting functions (GetProvidedInterface() and SetRequiredInterface()) to the instantiated class. And, also the TsmRun() function is forwarded to that user class.
public class UserForeign : TsmPComponent
{
private UserClass m_UserClass;
public UserForeign( TsmBase oParent, string sInstanceName )
{
m_UserClass = new UserClass( this, "UserClass" );
}
public override TsmInterfacePort GetProvidedInterface( string sPortName )
{
switch ( sPortName )
{
case "d_rp_User":
return m_UserClass.GetProvidedInterface( "UserPort" );
default:
break;
}
string s = "No port '" + sPortName + "' @ UserComponent";
throw new TsmException( s );
}
public override void SetRequiredInterface( string sPortName, TsmInterfacePort oProvidedInterface )
{
switch ( sPortName )
{
case "d_rp_User":
m_UserClass.SetRequiredInterface( "UserPort", oProvidedInterface );
return;
default:
break;
}
string s = "No port '" + sPortName + "' @ UserComponent";
throw new TsmException( s );
}
public override void TsmRun( object oObject )
{
m_UserClass.TsmRun( oObject );
}
}
This class implements the port that is the access point to the foreign component and hence to the component's instantiated UserClass. The port inherits from the modeled interface TsmIPort_ICbCtlrServer, that is the class of the port known by the invoking controller. Note that TsmIPort_ICbCtlrServer on its turn inherits from interface ICbCtlrServer. So, this port realises function CbStarted(), which forwards the call to the UserClass.
public class MyTsmIPort_ICbCtlrServer : TsmIPort_ICbCtlrServer
{
private UserClass m_UserClass;
public MyTsmIPort_ICbCtlrServer( UserClass oParent )
: base( oParent )
{
m_UserClass = oParent;
}
public override void CbStarted( float fCbStart )
{
m_UserClass.CbStarted( fCbStart );
}
}
This class implements the 2 functions (GetProvidedInterface() and SetRequiredInterface()) for
connecting to the controller. It provides its own port TsmPI__Port that has been created
in the constructor. And it receives the port named Port from the controller.
Furthermore, the provided interface (IDriverServer)
has been implemented with the function Begin().
Note the remark "Do NOT
fill in Port.Source !!" . In the mocks (where this code
can be copied from) the Source
field is filled in on behalf of logging. Filling it here would corrupt
the logging.
public class DriverClass : TsmClass, IDriverServer
{
private MyTsmIPort_IDriverServer TsmPI__Port;
private TsmIPort_ICbDriverServer Port;
private double dPar = 1.0;
private long L10 = 55;
public DriverClass( TsmBase oParent, string sInstanceName )
{
TsmPI__Port = new MyTsmIPort_IDriverServer( this );
}
public override TsmInterfacePort GetProvidedInterface( string sPortName )
{
switch ( sPortName )
{
case "DriverPort":
return TsmPI__Port;
default:
break;
}
string s = "No port '" + sPortName + "' @ DriverClass";
throw new TsmException( s );
}
public override void SetRequiredInterface( string sPortName, TsmInterfacePort oProvidedInterface )
{
switch ( sPortName )
{
case "DriverPort":
Port = (TsmIPort_ICbDriverServer) oProvidedInterface;
// Do NOT fill in Port.Source !!
return;
default:
break;
}
string s = "No port '" + sPortName + "' @ DriverClass";
throw new TsmException( s );
}
// ( DriverServerPsm >> Beginning ) => ( DriverServerPsm >> Idle )
public long Begin( int iPar )
{
Port.CbBegin( dPar );
return L10;
}
}
This class of the foreign component instantiates the DriverClass in its descriptor. It forwards the 2 connecting functions (GetProvidedInterface() and SetRequiredInterface()) to the instantiated class.
public class DriverForeign : TsmPComponent
{
private DriverClass m_DriverClass;
public DriverForeign( TsmBase oParent, string sInstanceName )
{
m_DriverClass = new DriverClass( this, "DriverClass" );
}
public override TsmInterfacePort GetProvidedInterface( string sPortName )
{
switch ( sPortName )
{
case "d_pp_Driver":
return m_DriverClass.GetProvidedInterface( "DriverPort" );
default:
break;
}
string s = "No port '" + sPortName + "' @ DriverForeign";
throw new TsmException( s );
}
public override void SetRequiredInterface( string sPortName, TsmInterfacePort oProvidedInterface )
{
switch ( sPortName )
{
case "d_pp_Driver":
m_DriverClass.SetRequiredInterface( "DriverPort", oProvidedInterface );
return;
default:
break;
}
string s = "No port '" + sPortName + "' @ DriverForeign";
throw new TsmException( s );
}
}
This class implements the port that is the access point to the foreign component and hence to the component's instantiated DriverClass. The port inherits from the modeled interface TsmIPort_IDriverServer, that is the class of the port known by the invoking controller. Note that TsmIPort_IDriverServer on its turn inherits from interface IDriverServer. So, this port realises function Begin(), which forwards the call to the DriverClass.
public class MyTsmIPort_IDriverServer : TsmIPort_IDriverServer
{
private DriverClass m_DriverClass;
public MyTsmIPort_IDriverServer( DriverClass oParent )
: base( oParent )
{
m_DriverClass = oParent;
}
public override long Begin( int iPar )
{
return m_DriverClass.Begin( iPar );
}
}
The realisation of the foreign components in Java is almost the same
as the realisation in C#. The differences refer mostly to the syntactic
sugar.
Therefore, the accompanying remarks are similar to C#.
This class implements the 2 functions (GetProvidedInterface() and SetRequiredInterface()) for
connecting to the controller. It provides its own port TsmPI__Port that has been created
in the constructor. And it receives the port named Port from the controller.
Furthermore, the (overridden) TsmRun()
function is responsible for all the activity of triggering the
controller and waiting for the response. Finally, the provided
interface (ICbCtlrServer) has
been implemented with the callback function CbStarted().
Note the remark "Do NOT
fill in Port.Source !!" . In the mocks (where this code
can be copied from) the Source
field is filled in on behalf of logging. Filling it here would corrupt
the logging.
class UserClass extends TsmClass implements ICbCtlrServer
{
private MyTsmIPort_ICbCtlrServer TsmPI__Port;
private TsmIPort_ICtlrServer Port;
private int iRv = 0;
private boolean bCallback = false;
public UserClass( TsmBase oParent, String sInstanceName )
{
TsmPI__Port = new MyTsmIPort_ICbCtlrServer( this );
}
@Override
public TsmInterfacePort GetProvidedInterface( String sPortName )
{
if ( sPortName.equals( "UserPort" ) )
{
return TsmPI__Port;
}
String s = "No port '" + sPortName + "' @ UserClass";
throw new TsmException( s );
}
@Override
public void SetRequiredInterface( String sPortName, TsmInterfacePort oProvidedInterface )
{
if ( sPortName.equals( "UserPort" ) )
{
Port = (TsmIPort_ICtlrServer) oProvidedInterface;
// Do NOT fill in Port.Source !!
return;
}
String s = "No port '" + sPortName + "' @ UserClass";
throw new TsmException( s );
}
@Override
public void TsmRun( Object oObject )
{
this.iRv = Port.Start(true);
try
{
// Wait for response from callback function.
// Use global variable and non-busy polling for synchronisation.
while ( !bCallback )
{
Thread.sleep( 100 );
}
// Grant time to CbThread to finish its callback activity.
Thread.sleep( 1000 );
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
// ( UserClientPsm >> Starting ) => ( UserClientPsm >> Idle )
public void CbStarted( float fCbStart )
{
Tsm.Log( "CbStarted" );
bCallback = true;
}
}
This class of the foreign component instantiates the UserClass in its descriptor. It forwards the 2 connecting functions (GetProvidedInterface() and SetRequiredInterface()) to the instantiated class. And, also the TsmRun() function is forwarded to that user class.
public class UserForeign extends TsmPComponent
{
private UserClass m_UserClass;
public UserForeign( TsmBase oParent, String sInstanceName )
{
m_UserClass = new UserClass( this, "UserClass" );
}
@Override
public TsmInterfacePort GetProvidedInterface( String sPortName )
{
if ( sPortName.equals( "d_rp_User" ) )
{
return m_UserClass.GetProvidedInterface( "UserPort" );
}
String s = "No port '" + sPortName + "' @ UserForeign";
throw new TsmException( s );
}
@Override
public void SetRequiredInterface( String sPortName, TsmInterfacePort oProvidedInterface )
{
if ( sPortName.equals( "d_rp_User" ) )
{
m_UserClass.SetRequiredInterface( "UserPort", oProvidedInterface );
return;
}
String s = "No port '" + sPortName + "' @ UserForeign";
throw new TsmException( s );
}
@Override
public void TsmRun( Object oObject )
{
m_UserClass.TsmRun( oObject );
}
}
This class implements the port that is the access point to the foreign component and hence to the component's instantiated UserClass. The port inherits from the modeled interface TsmIPort_ICbCtlrServer, that is the class of the port known by the invoking controller. Note that TsmIPort_ICbCtlrServer on its turn inherits from interface ICbCtlrServer. So, this port realises function CbStarted(), which forwards the call to the UserClass.
class MyTsmIPort_ICbCtlrServer extends TsmIPort_ICbCtlrServer
{
private UserClass m_UserClass;
public MyTsmIPort_ICbCtlrServer( UserClass oParent )
{
super( oParent );
m_UserClass = oParent;
}
@Override
public void CbStarted( float fCbStart )
{
m_UserClass.CbStarted( fCbStart );
}
}
This class implements the 2 functions (GetProvidedInterface() and SetRequiredInterface()) for
connecting to the controller. It provides its own port TsmPI__Port that has been created
in the constructor. And it receives the port named Port from the controller.
Furthermore, the provided interface (IDriverServer)
has been implemented with the function Begin().
Note the remark "Do NOT
fill in Port.Source !!" . In the mocks (where this code
can be copied from) the Source
field is filled in on behalf of logging. Filling it here would corrupt
the logging.
class DriverClass extends TsmClass implements IDriverServer
{
private MyTsmIPort_IDriverServer TsmPI__Port;
private TsmIPort_ICbDriverServer Port;
private double dPar = 1.0;
private long L10 = 55;
public DriverClass( TsmBase oParent, String sInstanceName )
{
TsmPI__Port = new MyTsmIPort_IDriverServer( this );
}
@Override
public TsmInterfacePort GetProvidedInterface( String sPortName )
{
if ( sPortName.equals( "DriverPort" ) )
{
return TsmPI__Port;
}
String s = "No port '" + sPortName + "' @ DriverClass";
throw new TsmException( s );
}
@Override
public void SetRequiredInterface( String sPortName, TsmInterfacePort oProvidedInterface )
{
if ( sPortName.equals( "DriverPort" ) )
{
Port = (TsmIPort_ICbDriverServer) oProvidedInterface;
// Do NOT fill in Port.Source !!
return;
}
String s = "No port '" + sPortName + "' @ DriverClass";
throw new TsmException( s );
}
// ( DriverServerPsm >> Beginning ) => ( DriverServerPsm >> Idle )
@Override
public long Begin( int iPar )
{
Port.CbBegin( dPar );
return L10;
}
}
This class of the foreign component instantiates the DriverClass in its descriptor. It forwards the 2 connecting functions (GetProvidedInterface() and SetRequiredInterface()) to the instantiated class.
public class DriverForeign extends TsmPComponent
{
private DriverClass m_DriverClass;
public DriverForeign( TsmBase oParent, String sInstanceName )
{
m_DriverClass = new DriverClass( this, "DriverClass" );
}
@Override
public TsmInterfacePort GetProvidedInterface( String sPortName )
{
if ( sPortName.equals( "d_pp_Driver" ) )
{
return m_DriverClass.GetProvidedInterface( "DriverPort" );
}
String s = "No port '" + sPortName + "' @ DriverForeign";
throw new TsmException( s );
}
@Override
public void SetRequiredInterface( String sPortName, TsmInterfacePort oProvidedInterface )
{
if ( sPortName.equals( "d_pp_Driver" ) )
{
m_DriverClass.SetRequiredInterface( "DriverPort", oProvidedInterface );
return;
}
String s = "No port '" + sPortName + "' @ DriverForeign";
throw new TsmException( s );
}
}
This class implements the port that is the access point to the foreign component and hence to the component's instantiated DriverClass. The port inherits from the modeled interface TsmIPort_IDriverServer, that is the class of the port known by the invoking controller. Note that TsmIPort_IDriverServer on its turn inherits from interface IDriverServer. So, this port realises function Begin(), which forwards the call to the DriverClass.
class MyTsmIPort_IDriverServer extends TsmIPort_IDriverServer
{
private DriverClass m_DriverClass;
public MyTsmIPort_IDriverServer( DriverClass oParent )
{
super( oParent );
m_DriverClass = oParent;
}
@Override
public long Begin( int iPar )
{
return m_DriverClass.Begin( iPar );
}
}
The realisation of the foreign components in C++ is basically the same as the realisation in C# or Java. The main differences concern the subdivision of the definitions in a header file and the implementation in a source file.
The header file User.h of the foreign User component contains the definitions of the 3 classes. Note that all functions for MyTsmIPort_ICbCtlrServer are defined here by inline functions.
class MyTsmIPort_ICbCtlrServer;
class UserClass : public TsmClass, public ICbCtlrServer
{
private:
TsmIPort_ICtlrServer* Port;
MyTsmIPort_ICbCtlrServer* TsmPI__Port;
int iRv;
bool bCallback;
public:
UserClass( TsmBase* oParent, string sInstanceName );
virtual ~UserClass();
TsmInterfacePort* GetProvidedInterface( string sPortName );
void SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface );
void TsmRun( void* oObject );
void CbStarted( float fCbStart );
};
class UserForeign : public TsmPComponent
{
private:
UserClass* m_UserClass;
public:
UserForeign( TsmBase* oParent, string sInstanceName );
~UserForeign();
TsmInterfacePort* GetProvidedInterface( string sPortName );
void SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface );
void TsmRun( void* oObject );
};
class MyTsmIPort_ICbCtlrServer : public TsmIPort_ICbCtlrServer
{
private:
UserClass* m_UserClass;
public:
MyTsmIPort_ICbCtlrServer( UserClass* oParent )
: TsmIPort_ICbCtlrServer( oParent )
, m_UserClass( oParent )
{
}
void CbStarted( float fCbStart )
{
m_UserClass->CbStarted( fCbStart );
}
};
This class implements the 2 functions (GetProvidedInterface() and SetRequiredInterface()) for
connecting to the controller. It provides its own port TsmPI__Port that has been created
in the constructor. And it receives the port named Port from the controller.
Furthermore, the (overridden) TsmRun()
function is responsible for all the activity of triggering the
controller and waiting for the response. Finally, the provided
interface (ICbCtlrServer) has
been implemented with the callback function CbStarted().
Note the remark "Do NOT
fill in Port->Source !!" . In the mocks (where this
code can be copied from) the Source
field is filled in on behalf of logging. Filling it here would corrupt
the logging.
UserClass::UserClass( TsmBase* oParent, string sInstanceName )
: bCallback( false )
{
TsmPI__Port = new MyTsmIPort_ICbCtlrServer( this );
}
UserClass::~UserClass()
{
delete TsmPI__Port;
}
TsmInterfacePort* UserClass::GetProvidedInterface( string sPortName )
{
if ( sPortName == "UserPort" )
{
return TsmPI__Port;
}
string s = "No port '" + sPortName + "' @ UserClass";
throw TsmException( s );
}
void UserClass::SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface )
{
if ( sPortName == "UserPort" )
{
Port = static_cast(oProvidedInterface);
// Do NOT fill in Port->Source !!
return;
}
string s = "No port '" + sPortName + "' @ UserClass";
throw TsmException( s );
}
void UserClass::TsmRun( void* oObject )
{
this->iRv = this->Port->Start( true);
// Wait for response from callback function.
// Use global variable and non-busy polling for synchronisation.
while ( !this->bCallback )
{
boost::posix_time::milliseconds ms(100);
boost::this_thread::sleep( ms );
}
// Grant time to CbThread to finish its callback activity.
boost::posix_time::milliseconds ms2(1000);
boost::this_thread::sleep( ms2 );
}
void UserClass::CbStarted( float fCbStart )
{
Tsm::Log( "CbStarted" );
this->bCallback = true;
}
This class of the foreign component instantiates the UserClass in its descriptor. It forwards the 2 connecting functions (GetProvidedInterface() and SetRequiredInterface()) to the instantiated class. And, also the TsmRun() function is forwarded to that user class .
UserForeign::UserForeign( TsmBase* oParent, string sInstanceName )
{
m_UserClass = new UserClass( this, "UserClass" );
}
UserForeign::~UserForeign()
{
delete m_UserClass;
}
TsmInterfacePort* UserForeign::GetProvidedInterface( string sPortName )
{
if ( sPortName == "d_rp_User" )
{
return m_UserClass->GetProvidedInterface( "UserPort" );
}
string s = "No port '" + sPortName + "' @ UserForeign";
throw TsmException( s );
}
void UserForeign::SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface )
{
if ( sPortName == "d_rp_User" )
{
m_UserClass->SetRequiredInterface( "UserPort", oProvidedInterface );
return;
}
string s = "No port '" + sPortName + "' @ UserForeign";
throw TsmException( s );
}
void UserForeign::TsmRun( void* oObject )
{
m_UserClass->TsmRun( oObject );
}
The header file Driver.h of the foreign Driver component contains the definitions of the 3 classes. Note that all functions for MyTsmIPort_IDriverServer are defined here by inline functions.
class MyTsmIPort_IDriverServer;
class DriverClass : public TsmClass, public IDriverServer
{
private:
MyTsmIPort_IDriverServer* TsmPI__Port;
TsmIPort_ICbDriverServer* Port;
double dPar;
long L10;
public:
DriverClass( TsmBase* oParent, string sInstanceName );
virtual ~DriverClass();
TsmInterfacePort* GetProvidedInterface( string sPortName );
void SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface );
// ( DriverServerPsm >> Beginning ) => ( DriverServerPsm >> Idle )
long Begin( int iPar );
};
class DriverForeign : public TsmPComponent
{
private:
DriverClass* m_DriverClass;
public:
DriverForeign( TsmBase* oParent, string sInstanceName );
virtual ~DriverForeign();
TsmInterfacePort* GetProvidedInterface( string sPortName );
void SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface );
};
class MyTsmIPort_IDriverServer : public TsmIPort_IDriverServer
{
private:
DriverClass* m_DriverClass;
public:
MyTsmIPort_IDriverServer( DriverClass* oParent )
: TsmIPort_IDriverServer( oParent )
, m_DriverClass( oParent )
{
}
long Begin( int iPar )
{
return m_DriverClass->Begin( iPar );
}
};
This class implements the 2 functions (GetProvidedInterface() and SetRequiredInterface()) for
connecting to the controller. It provides its own port TsmPI__Port that has been created
in the constructor. And it receives the port named Port from the controller.
Furthermore, the provided interface (IDriverServer)
has been implemented with the function Begin().
Note the remark "Do NOT
fill in Port->Source !!" . In the mocks (where this
code can be copied from) the Source
field is filled in on behalf of logging. Filling it here would corrupt
the logging.
DriverClass::DriverClass( TsmBase* oParent, string sInstanceName )
: dPar( 1.0 )
, L10( 55 )
{
TsmPI__Port = new MyTsmIPort_IDriverServer( this );
}
DriverClass::~DriverClass()
{
delete TsmPI__Port;
}
TsmInterfacePort* DriverClass::GetProvidedInterface( string sPortName )
{
if ( sPortName == "DriverPort" )
{
return TsmPI__Port;
}
string s = "No port '" + sPortName + "' @ DriverClass";
throw TsmException( s );
}
void DriverClass::SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface )
{
if ( sPortName == "DriverPort" )
{
Port = static_cast(oProvidedInterface);
// Do NOT fill in Port->Source !!
return;
}
string s = "No port '" + sPortName + "' @ DriverClass";
throw TsmException( s );
}
// ( DriverServerPsm >> Beginning ) => ( DriverServerPsm >> Idle )
long DriverClass::Begin( int iPar )
{
Port->CbBegin( dPar );
return L10;
}
This class of the foreign component instantiates the DriverClass in its descriptor. It forwards the 2 connecting functions (GetProvidedInterface() and SetRequiredInterface()) to the instantiated class.
DriverForeign::DriverForeign( TsmBase* oParent, string sInstanceName )
{
m_DriverClass = new DriverClass( this, "DriverClass" );
}
DriverForeign::~DriverForeign()
{
delete m_DriverClass;
}
TsmInterfacePort* DriverForeign::GetProvidedInterface( string sPortName )
{
if ( sPortName == "d_pp_Driver" )
{
return m_DriverClass->GetProvidedInterface( "DriverPort" );
}
string s = "No port '" + sPortName + "' @ DriverForeign";
throw TsmException( s );
}
void DriverForeign::SetRequiredInterface( string sPortName, TsmInterfacePort* oProvidedInterface )
{
if ( sPortName == "d_pp_Driver" )
{
m_DriverClass->SetRequiredInterface( "DriverPort", oProvidedInterface );
return;
}
string s = "No port '" + sPortName + "' @ DriverForeign";
throw TsmException( s );
}
The realisation of the foreign components in C resembles the realisation in C++. The main differences deal with the emulation of object oriented semantics. The implementation of a component consists of the definitions in an include file and the functions in a source file.
The header file User.h of the foreign User component contains the type definitions of the structures for the 3 "classes" and their function prototypes.
typedef struct UserClassStruct
{
#include "TsmClass_fields.h"
void (*CbStarted)( struct UserClassStruct* this, float fCbStart );
struct MyTsmIPort_ICbCtlrServerStruct* TsmPI__Port;
TsmIPort_ICtlrServer* Port;
int iRv;
TsmBool bCallback;
} UserClass;
UserClass* UserClass_Ctor( TsmBase* oParent, char* sInstanceName );
void UserClass_Gtor( struct UserClassStruct* this );
TsmInterfacePort* UserClass_GetProvidedInterface( struct UserClassStruct* this, char* sPortName );
void UserClass_SetRequiredInterface( struct UserClassStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface );
void UserClass_TsmRun( struct UserClassStruct* this, void* oObject );
void UserClass_CbStarted( struct UserClassStruct* this, float fCbStart );
typedef struct UserForeignStruct
{
#include "TsmPComponent_fields.h"
UserClass* m_UserClass;
} UserForeign;
UserForeign* UserForeign_Ctor( TsmBase* oParent, char* sInstanceName );
TsmInterfacePort* UserForeign_GetProvidedInterface( struct UserForeignStruct* this, char* sPortName );
void UserForeign_SetRequiredInterface( struct UserForeignStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface );
void UserForeign_TsmRun( struct UserForeignStruct* this, void* oObject );
typedef struct MyTsmIPort_ICbCtlrServerStruct /* copied from TsmIPort_ICbCtlrServerStruct */
{
#include "TsmInterfacePort_fields.h"
void (*CbStarted)( struct MyTsmIPort_ICbCtlrServerStruct* this, float fCbStart );
struct UserClassStruct* m_UserClass;
} MyTsmIPort_ICbCtlrServer;
MyTsmIPort_ICbCtlrServer* MyTsmIPort_ICbCtlrServer_Ctor( TsmBase* oParent );
void MyTsmIPort_ICbCtlrServer_CbStarted( struct MyTsmIPort_ICbCtlrServerStruct* this, float fCbStart );
This class implements several functions including the 2 functions for connecting to the controller. The constructor UserClass_Ctor shows how an object is created. We will dive into it to explain the object oriented semantics.
Note the remark "Do NOT fill in Port->Source !!" . In the mocks (where this code can be copied from) the Source field is filled in on behalf of logging. Filling it here would corrupt the logging.
UserClass* UserClass_Ctor( TsmBase* oParent, char* sInstanceName )
{
UserClass* this = (UserClass*) Tsm_Malloc( sizeof(UserClass) );
TsmClass_Ftor( (TsmClass*) this );
this->GetProvidedInterface = (Tsm_pfClPrvIfc) UserClass_GetProvidedInterface;
this->SetRequiredInterface = (Tsm_pfClReqIfc) UserClass_SetRequiredInterface;
this->TsmRun = (Tsm_pfClVoid) UserClass_TsmRun;
this->Gtor = (Tsm_pfObj) UserClass_Gtor;
this->CbStarted = UserClass_CbStarted;
this->TsmPI__Port = MyTsmIPort_ICbCtlrServer_Ctor( (TsmBase*) this );
this->iRv = 0;
this->bCallback = FALSE;
return this;
}
void UserClass_Gtor( struct UserClassStruct* this )
{
this->TsmPI__Port->Dtor( (TsmObject*) this->TsmPI__Port );
TsmClass_Gtor( (TsmClass*) this );
}
TsmInterfacePort* UserClass_GetProvidedInterface( struct UserClassStruct* this, char* sPortName )
{
char* s;
if ( 0==strcmp( sPortName, "UserPort" ) )
{
return (TsmInterfacePort*) this->TsmPI__Port;
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ UserClass", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
return NULL;
}
void UserClass_SetRequiredInterface( struct UserClassStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface )
{
char* s;
if ( 0==strcmp( sPortName, "UserPort" ) )
{
this->Port = (TsmIPort_ICtlrServer*) oProvidedInterface;
/* Do NOT fill in Port->Source !! */
return;
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ UserClass", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
}
void UserClass_TsmRun( struct UserClassStruct* this, void* oObject )
{
this->iRv = this->Port->Start( this->Port, TRUE);
/*
* Wait for response from callback function.
* Use global variable and non-busy polling for synchronisation.
*/
while ( !this->bCallback )
{
OSAL_ThreadSleep( 100 );
}
/* Grant time to CbThread to finish its callback activity. */
OSAL_ThreadSleep( 1000 );
}
/* ( UserClientPsm >> Starting ) => ( UserClientPsm >> Idle ) */
void UserClass_CbStarted( struct UserClassStruct* this, float fCbStart )
{
Tsm_Log( "CbStarted" );
this->bCallback = TRUE;
}
This class of the foreign component instantiates the UserClass. It delegates the 2 connecting functions to the instantiated class. And, also a TsmRun() function is needed for that user class .
UserForeign* UserForeign_Ctor( TsmBase* oParent, char* sInstanceName )
{
UserForeign* this = (UserForeign*) Tsm_Malloc( sizeof(UserForeign) );
TsmPComponent_Ftor( (TsmPComponent*) this );
this->GetProvidedInterface = (Tsm_pfClPrvIfc) UserForeign_GetProvidedInterface;
this->SetRequiredInterface = (Tsm_pfClReqIfc) UserForeign_SetRequiredInterface;
this->TsmRun = (Tsm_pfClVoid) UserForeign_TsmRun;
this->m_UserClass = UserClass_Ctor( (TsmBase*) this, "UserClass" );
return this;
}
TsmInterfacePort* UserForeign_GetProvidedInterface( struct UserForeignStruct* this, char* sPortName )
{
char* s;
if ( 0==strcmp( sPortName, "d_rp_User" ) )
{
return this->m_UserClass->GetProvidedInterface( (TsmClass*) this->m_UserClass, "UserPort" );
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ UserForeign", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
return NULL;
}
void UserForeign_SetRequiredInterface( struct UserForeignStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface )
{
char* s;
if ( 0==strcmp( sPortName, "d_rp_User" ) )
{
this->m_UserClass->SetRequiredInterface( (TsmClass*) this->m_UserClass, "UserPort", oProvidedInterface );
return;
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ UserForeign", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
}
void UserForeign_TsmRun( struct UserForeignStruct* this, void* oObject )
{
this->m_UserClass->TsmRun( (TsmClass*) this->m_UserClass, oObject );
}
This class implements the port that is the access point to the foreign component and hence to the component's instantiated UserClass. The port inherits from the modeled interface TsmIPort_ICbCtlrServer, that is the class of the port known by the invoking controller. Note that TsmIPort_ICbCtlrServer on its turn inherits from class TsmInterfacePort and from interface ICbCtlrServer. Therefore, the fields from TsmInterfacePort are copied to this ; and the function pointer CbStarted is filled with the address of our function MyTsmIPort_ICbCtlrServer_CbStarted, that implements the provided interface ICbCtlrServer. So, this port realises function CbStarted(), which forwards the call to the UserClass.
MyTsmIPort_ICbCtlrServer* MyTsmIPort_ICbCtlrServer_Ctor( TsmBase* oParent )
{
MyTsmIPort_ICbCtlrServer* this = (MyTsmIPort_ICbCtlrServer*) Tsm_Malloc( sizeof(MyTsmIPort_ICbCtlrServer) );
TsmInterfacePort_Ftor( (TsmInterfacePort*) this );
this->CbStarted = MyTsmIPort_ICbCtlrServer_CbStarted;
this->m_UserClass = (struct UserClassStruct*) oParent;
return this;
}
void MyTsmIPort_ICbCtlrServer_CbStarted( struct MyTsmIPort_ICbCtlrServerStruct* this, float fCbStart )
{
this->m_UserClass->CbStarted( this->m_UserClass, fCbStart );
}
The header file Driver.h of the foreign Driver component contains the type definitions of the structures for the 3 "classes" and their function prototypes.
typedef struct DriverClassStruct
{
#include "TsmClass_fields.h"
struct MyTsmIPort_IDriverServerStruct* TsmPI__Port;
TsmIPort_ICbDriverServer* Port;
double dPar;
long L10;
} DriverClass;
DriverClass* DriverClass_Ctor( TsmBase* oParent, char* sInstanceName );
void DriverClass_Gtor( struct DriverClassStruct* this );
TsmInterfacePort* DriverClass_GetProvidedInterface( struct DriverClassStruct* this, char* sPortName );
void DriverClass_SetRequiredInterface( struct DriverClassStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface );
typedef struct DriverForeignStruct
{
#include "TsmPComponent_fields.h"
DriverClass* m_DriverClass;
} DriverForeign;
DriverForeign* DriverForeign_Ctor( TsmBase* oParent, char* sInstanceName );
TsmInterfacePort* DriverForeign_GetProvidedInterface( struct DriverForeignStruct* this, char* sPortName );
void DriverForeign_SetRequiredInterface( struct DriverForeignStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface );
typedef struct MyTsmIPort_IDriverServerStruct /* copied from TsmIPort_IDriverServerStruct */
{
#include "TsmInterfacePort_fields.h"
long (*Begin)( struct MyTsmIPort_IDriverServerStruct* this, int iPar );
struct DriverClassStruct* m_DriverClass;
} MyTsmIPort_IDriverServer;
MyTsmIPort_IDriverServer* MyTsmIPort_IDriverServer_Ctor( TsmBase* oParent );
long MyTsmIPort_IDriverServer_Begin( struct MyTsmIPort_IDriverServerStruct* this, int iPar );
This class implements several functions including the 2 functions for connecting to the controller. The constructor DriverClass_Ctor shows how an object is created. We will dive into it to explain the object oriented semantics.
Note the remark "Do NOT fill in Port->Source !!" . In the mocks (where this code can be copied from) the Source field is filled in on behalf of logging. Filling it here would corrupt the logging.
DriverClass* DriverClass_Ctor( TsmBase* oParent, char* sInstanceName )
{
DriverClass* this = (DriverClass*) Tsm_Malloc( sizeof(DriverClass) );
TsmClass_Ftor( (TsmClass*) this );
this->GetProvidedInterface = (Tsm_pfClPrvIfc) DriverClass_GetProvidedInterface;
this->SetRequiredInterface = (Tsm_pfClReqIfc) DriverClass_SetRequiredInterface;
this->Gtor = (Tsm_pfObj) DriverClass_Gtor;
this->TsmPI__Port = MyTsmIPort_IDriverServer_Ctor( (TsmBase*) this );
this->dPar = 1.0;
this->L10 = 55;
return this;
}
void DriverClass_Gtor( struct DriverClassStruct* this )
{
this->TsmPI__Port->Dtor( (TsmObject*) this->TsmPI__Port );
TsmClass_Gtor( (TsmClass*) this );
}
TsmInterfacePort* DriverClass_GetProvidedInterface( struct DriverClassStruct* this, char* sPortName )
{
char* s;
if ( 0==strcmp( sPortName, "DriverPort" ) )
{
return (TsmInterfacePort*) this->TsmPI__Port;
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ DriverClass", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
return NULL;
}
void DriverClass_SetRequiredInterface( struct DriverClassStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface )
{
char* s;
if ( 0==strcmp( sPortName, "DriverPort" ) )
{
this->Port = (TsmIPort_ICbDriverServer*) oProvidedInterface;
/* Do NOT fill in Port->Source !! */
return;
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ DriverClass", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
}
/* ( DriverServerPsm >> Beginning ) => ( DriverServerPsm >> Idle ) */
long DriverClass_Begin( struct DriverClassStruct* this, int iPar )
{
this->Port->CbBegin( this->Port, this->dPar );
return this->L10;
}
This class of the foreign component instantiates the DriverClass. It delegates the 2 connecting functions to the instantiated class.
DriverForeign* DriverForeign_Ctor( TsmBase* oParent, char* sInstanceName )
{
DriverForeign* this = (DriverForeign*) Tsm_Malloc( sizeof(DriverForeign) );
TsmPComponent_Ftor( (TsmPComponent*) this );
this->GetProvidedInterface = (Tsm_pfClPrvIfc) DriverForeign_GetProvidedInterface;
this->SetRequiredInterface = (Tsm_pfClReqIfc) DriverForeign_SetRequiredInterface;
this->m_DriverClass = DriverClass_Ctor( (TsmBase*) this, "DriverClass" );
return this;
}
TsmInterfacePort* DriverForeign_GetProvidedInterface( struct DriverForeignStruct* this, char* sPortName )
{
char* s;
if ( 0==strcmp( sPortName, "d_pp_Driver" ) )
{
return this->m_DriverClass->GetProvidedInterface( (TsmClass*) this->m_DriverClass, "DriverPort" );
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ DriverForeign", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
return NULL;
}
void DriverForeign_SetRequiredInterface( struct DriverForeignStruct* this, char* sPortName, TsmInterfacePort* oProvidedInterface )
{
char* s;
if ( 0==strcmp( sPortName, "d_pp_Driver" ) )
{
this->m_DriverClass->SetRequiredInterface( (TsmClass*) this->m_DriverClass, "DriverPort", oProvidedInterface );
return;
}
s = Tsm_Malloc( TSM_NCH_FULLNAME );
sprintf( s, "No port '%s' @ DriverForeign", sPortName );
TsmException_Quit( s );
Tsm_Free( s );
}
This class implements the port that is the access point to the foreign component and hence to the component's instantiated DriverClass. The port inherits from the modeled interface TsmIPort_IDriverServer, that is the class of the port known by the invoking controller. Note that TsmIPort_IDriverServer on its turn inherits from class TsmInterfacePort and from interface IDriverServer. Therefore, the fields from TsmInterfacePort are copied to this ; and the function pointer Begin is filled with the address of our function MyTsmIPort_ IDriverServer_Begin, that implements the provided interface IDriverServer. So, this port realises function Begin(), which forwards the call to the DriverClass.
MyTsmIPort_IDriverServer* MyTsmIPort_IDriverServer_Ctor( TsmBase* oParent )
{
MyTsmIPort_IDriverServer* this = (MyTsmIPort_IDriverServer*) Tsm_Malloc( sizeof(MyTsmIPort_IDriverServer) );
TsmInterfacePort_Ftor( (TsmInterfacePort*) this );
this->Begin = MyTsmIPort_IDriverServer_Begin;
this->m_DriverClass = (DriverClass*) oParent;
return this;
}
long MyTsmIPort_IDriverServer_Begin( struct MyTsmIPort_IDriverServerStruct* this, int iPar )
{
return DriverClass_Begin( this->m_DriverClass, iPar );
}