4.2. Implementation example for extending the target-side

This section describes:

The class relationships are shown in Figure 4.1:

Figure 4.1. Custom extensions to a CADI interface class

To view this graphic, your browser must support the SVG format. Either install a browser with native support, or install an appropriate plugin such as Adobe SVG Viewer.


To create the target-side implementation:

  1. Declare the interface that provides the custom extensions in a new class. The class is called MyExtensions in Example 4.1:

    Example 4.1. MyExtensionsAbstract class

    // MyExtensions Interface Class
    // Keep this class as abstract as possible. It should be
    // the interface declaration, only.
    
    class MyExtensions
    	: public eslapi::CAInterface
    {
      public:
         static eslapi::if_name_t IFNAME()
            { return “MyExtensions”; }
         static eslapi::if_rev_t IFREVISION()
            { return 0; }
    
         virtual eslapi::CAInterface*
         ObtainInterface(eslapi::if_name_t ifName,
                         eslapi::if_rev_t  minRev,
                         eslapi::if_rev_t* actualRev);
      public:
         virtual void MyMethod1() = 0;
         virtual void MyMethod2() = 0;
         ...
    }
    

    The MyExtensions class is derived from eslapi::CAInterface to enable the extension mechanism. It must implement the IFNAME() and IFREVISION() methods. The remainder of the interface must be kept as abstract as possible provide a clean separation between the interface declaration and the interface implementation.

  2. It might not be obvious, but a CADI target that receives a custom extension interface also provides an implementation of the CADI interface itself. Enabling access to the custom extensions requires modification of the CADI implementation and, for Example 4.2, the passing of pointers from the instantiated interface objects.

    Example 4.2 shows the declaration of the class MyExtensionsImplementation that provides the actual implementation of the custom interface and some additions required to mount the new interface. The class MyCADI is the class derived from CADI as shown in Example 4.1.

    Example 4.2. Declaration of MyExtensionsImplementation

    // MyExtensionsImplementation Class
    // Implementing MyExtensions interface.
    class MyExtensionsImplementation
        : public MyExtensions
    {
    private:
        MyCADI *myCadiPointer; /* Pointer to an object of MyCADI which is
                                required for the link to the original interfaces.*/
    public:
        //Called by MyCADI constructor.
        MyExtensionsImplementation(MyCADI *myCadi)
        { myCadiPointer = myCadi; }
    
        static eslapi::if_name_t IFNAME()
        { return "MyExtensionsImplementation"; }
    
        static eslapi::if_rev_t IFREVISION()
        { return 0; }
    
        virtual eslapi::CAInterface*
        ObtainInterface(eslapi::if_name_t ifName,
                        eslapi::if_rev_t minRev,
                        eslapi::if_rev_t* actualRev);
    
    public:
        void MyMethod1();
        void MyMethod2();
    };
    

    This class owns a pointer of class MyCADI that points to the instance of the CADI implementation linked to this custom extension. This is required by the ObtainInterface() method as shown in Example 4.3. In this example, the corresponding pointer is passed through the constructor.

    This class must implement its own versions of the IFNAME() and IFREVISION() methods

  3. After declaring the MyExtensionsImplementation class, implement the inherited ObtainInterface() that receives the following parameters:

    ifname

    The interface name requested by the caller such as, for example, MyExtensionsImplementation.

    minRev

    The minimum revision required by the caller. Use 0 to accept any revision.

    actualRev

    The actually implemented revision (greater than or equal to minRev). This value must be set by the target.

    Example 4.3 shows a typical implementation of ObtainInterface() for the extension:

    Example 4.3. ObtainInterface()

    // Call ObtainInterface of MyCADI which is derived from CADI.
    // This guarantees that, for example, an ObtainInterface()
    // call for "eslapi.CAInterface" returns the same pointer
    // from MyExtensionsImplementation AND from MyCADI.
    eslapi::CAInterface*
    MyExtensionsImplementation::ObtainInterface(eslapi::if_name_t ifName,
                                                eslapi::if_rev_t minRev,
                                                eslapi::if_rev_t* actualRev)
    {
    	return myCadiPointer->ObtainInterface(ifName, minRev, actualRev); 
    }
    

    This implementation forwards the interface request directly to the modified CADI implementation. The reasoning is to implement ObtainInterface() in exactly one place so that only one implementation must be edited if custom interfaces must be added. The CAInterface specification requires that the same pointer is provided for the specific requested interface, for example eslapi.CAInterface, for any call of ObtainInterface() from any class such as MyExtensionsImplementation::ObtainInterface() or myCadiPointer::ObtainInterface(). Because there is only one place to return these pointers, it can be guaranteed that the pointer for a requested interface is always the same.

  4. The final step to implement and mount a custom extension interface is to modify the existing CADI implementation by deriving it and the required code as shown in Example 4.4:

    Example 4.4. Changes to MyCADI class

    // MyCADI Class
    // Derived from class CADI. The main purpose is to
    // provide the modified ObtainInterface() method.
    class MyCADI
    	: public eslapi::CADI
    {
    private:
    	MyExtensionsImplementation* myExtensionsPointer;
    
    public:
    	MyCADI()
    	{ myExtensionsPointer = new MyExtensionsImplementation(this); }
    
    	static eslapi::if_name_t IFNAME()
    	{ return "MyCADI"; }
    
    	static eslapi::if_rev_t IFREVISION()
    	{ return 0; }
    
    	virtual eslapi::CAInterface*
    	ObtainInterface(eslapi::if_name_t ifName,	
    					eslapi::if_rev_t minRev,
    					eslapi::if_rev_t* actualRev);
    
    	// …
    };
    

    In Example 4.4, an instance of MyExtensionsImplementation is owned by MyCADI. This is instantiated in the class constructor and accessed through a pointer. It is required to support calling the ObtainInterface() implementation to return one of the interfaces such as MyExtensionsImplementation or MyExtensions.

The value of the MyExtensionsImplement class listed in Example 4.4 is the implementation of ObtainInterface() in the code fragment listed in Example 4.5:

Example 4.5. Using ObtainInterface()

// MyCADI has been chosen to provide the "central" ObtainInterface()
// method, i.e. all ObtainInterface() calls arriving in the target
// are routed to this implementation. This requires a corresponding
// check for all interfaces and pointers to all available interface
// instances. In this example we have to check for:
// - MyCADI
// - MyExtensionsImplementation
// - MyExtensions
// - CADI
// - CAInterface
eslapi::CAInterface*
MyCADI::ObtainInterface(eslapi::if_name_t ifName,
						eslapi::if_rev_t minRev,
						eslapi::if_rev_t* actualRev)
{
    // Check if queried interface is "MyCADI" and if the 
	// provided revision is sufficient.
	if((strcmp(ifName,IFNAME()) == 0)
	   && (minRev <= IFREVISION()))
	{
		if (actualRev != NULL) // NULL pointer check
		{
			*actualRev = IFREVISION(); // Set the actual rev
		}
		return this;
	}

    // Check if queried interface is "MyExtensionsImplementation" and
    // if the provided revision is sufficient.
	if((strcmp(ifName, MyExtensionsImplementation::IFNAME()) == 0)
	   && (minRev <= MyExtensionsImplementation::IFREVISION()))
	{
		if (actualRev != NULL) // NULL pointer check
		{
			*actualRev = MyExtensionsImplementation::IFREVISION();// Set the actual rev
		}
  // This is an additional check added for MyExtensionsImplementation,
  // return the corresponding pointer.
		return myExtensionsPointer;
	}

    // Check if queried interface is "MyExtensions" and if the 
	// provided revision is sufficient.
	if((strcmp(ifName, MyExtensions::IFNAME()) == 0)
	   && (minRev <= MyExtensions::IFREVISION()))
	{
		if (actualRev != NULL) // NULL pointer check
		{
	*actualRev = MyExtensions::IFREVISION(); // Set the actual rev
		}
  // This is an additional check added for MyExtensionsImplementation,
  // return the corresponding pointer.
		return myExtensionsPointer;
	}

    // Check if queried interface is "CADI" and if the 
	// provided revision is sufficient.
	if((strcmp(ifName, eslapi::CADI::IFNAME()) == 0)
	   && (minRev <= eslapi::CADI::IFREVISION()))
	{
		if (actualRev != NULL) // NULL pointer check
		{
	*actualRev = eslapi::CADI::IFREVISION(); // Set the actual rev
		}
		return this;
	}

    // Check if queried interface is "CAInterface" and if the 
	// provided revision is sufficient.
	if((strcmp(ifName, eslapi::CAInterface::IFNAME()) == 0)
	   && (minRev <= eslapi::CAInterface::IFREVISION()))
	{
		if (actualRev != NULL) // NULL pointer check
		{
*actualRev = eslapi::CAInterface::IFREVISION();// Set the actual rev
		}
		return this;
	}

	// Target does not provide the requested interface.
	return NULL;
}

Example 4.5 shows that this ObtainInterface() implementation is very similar to the common one. This example, however, has two interface checks associated with the added myExtensionsPointer pointer.

These interface checks are similar to the usual checks, but if one of the two interfaces is recognized, ObtainInterface() does not return the this pointer, but instead returns the pointer to the instantiated extension implementation myExtensionsPointer.

Copyright © 2008-2014 ARM. All rights reserved.ARM DUI 0444M
Non-ConfidentialID051314