Tuesday, June 28, 2011

Exploratory Project C++ Component Interface to the Ada Framework

Exploratory Project C++ Component Interface to the Ada Framework


General

A C++ component interface was created that is similar to that of the previous C interface posts.  That is, the App package Install procedure that is invoked from the Launch procedure from the applications main procedure calls a C++ initialize method in addition to that for the C initialize and the Ada initialize.  Similar to C, the C++ initialize calls the C++ topic Init methods and then the C++ component Install methods.  After all the components have been able to install themselves and register the topics that they will produce or need to consume, the App Launch procedure creates and starts the threads necessary to allow the components to run.

The diagram to illustrate the framework / component interface is updated as follows.


  <––––––––––general–––––––––><––––––––Application Specific––––––––––>
       +––––––+         +––––––––––+
       | Appn  |––––––––>|   Appn.   |
       | main |        /|  Launch  |
       +––––––+       / +––––––––––+
                     /   /    \
                 1  /  3/    2 \   <––– order of calls
    +––––––––––––+ /   /    +–––––––––+ a            +–––––––––––––––+
    |  mC.Itf.   |/   /     |  Appn.   |–––––––––––––>|     appn_       |
    | Initialize |   /      | Install |\             | InitializeAda |
    +––––––––––––+  /       +–––––––––+ \c           +–––––––––––––––+
                   /            |b       \                   |
                  /             v         \                  |
      +–––––––––+/        +–––––––––––––+  \                 |
      | mC.Itf. |         |    appn_     |   \                |
      | Start   |         | InitializeC |  +–––––––––––––+   |
      +–––––––––+         +–––––––––––––+  |    appn_     |   |
                                |          |InitializeCpp|   |
   rest of framework            |          +–––––––––––––+   |
    (mC, Exec, etc)             v               |            v
                           +–––––––––––+        v       +–––––––––––+
                           |  C com m  | +–––––––––––+  | Ada com m |
                           |  Install  | | C++ com m |  |  Install  |
                           +–––––––––––+ |  Install  |  +–––––––––––+
                                         +–––––––––––+

                                     application components


Because of initial difficulties linking the App-Install with the declaration
  procedure InitializeCpp;                              -- C++ common
  pragma Import(C, InitializeCpp, "app_InitializeCpp"); --  initialize
with C++ I created an intermediate step.  That is, app_InitializeCpp is C with the declaration and code
#include <AppC++.hh>

extern "C" void app_InitializeCpp()
{ // Initialize all C++ language topics and components.

  // Initialize each topic's internal data and install C++ components.
  AppCpp app;
  app.InitializeCppApp();

} // end method app_InitializeCpp
that, in turn, invokes the initialize of the AppCpp C++ class
#ifndef APPCPP
#define APPCPP

#include <com3C.hh>

class AppCpp
{

  public:

    // Initialize C++ App topics and install C++ components
    void InitializeCppApp(void);

    AppCpp(); // constructor

}; // end class AppCpp

#endif // APPCPP
that has the code
#include <AppC++.hh>
#include <Com3C.hh>
#include <mT_Topic_N_to_One_1.hh>
#include <mT_Topic_Periodic.hh>

Com3C component3C;
mT_Topic_N_to_One_1 topic_N_to_One_1;
mT_Topic_Periodic topic_Periodic;

void AppCpp::InitializeCppApp(void)
{
  topic_N_to_One_1.Init();
  topic_Periodic.Init();
  component3C.Install();

} // end method InitializeCppApp
to initialize two different topics as well as one C++ component.

Note:  Since this example is of an interface between a component written in C++ and the Ada framework (rather than of how to write C++) I have chosen to separate the class declarations in .hh files from the code in .cpp files and declare data objects in the code files.  Com3C.cpp will work with only one instance of the component object since there is only going to be one instance of the component class.  In general, this would be unlikely for topic classes (for instance, mT_Topic_N_to_One_1 or mT_Topic_Periodic) since more than one component could instantiate the class so its data, such as
mT_Topic::RegisterTopicParams dataRequest;
mT_Topic::RegisterTopicParams dataResponse;
might be used by multiple components at the same time.  Such concurrent use won't happen when registering the topic since that is done at install-time when there is only one thread.  But two callbacks could execute at the same time with one running and then getting suspended and another resuming, etc so that both could be using the data.  There is only one version of the data however, as set at install-time (via the Init calls in the InitializeCppApp method above), so this should not be a problem.

But there could be other cases where do want one instance of the class code and multiple instances of the data so that the code should be part of the class and instances of it should be created.

In order to have the linker recognize the Ada procedures for the Foreign C++ code to Register a component and topics or Read, Write or Publish an instance of a topic, the C extern declarations for the Ada Exports had to be modified.  For instance, the topic Register declared as
  procedure Register
  ( SubParams   : in Register_Topic_Subscription_Attributes_Ptr;
    --| Pointer to subscription parameters supplied by component
    TopicParams : in Register_Topic_Attributes_Ptr;
    --| Pointer to input parameters supplied by topic
    Status      : in Register_Topic_Status_Ptr;
    --| Register status to be returned
    Key         : in System.Address
    --| Key to be returned and supplied by component topic reader or writer
  );
  pragma Export(C, Register, "mC_Message_Foreign_RegisterCTopic" );

has a declaration in MessageForeign.hh of
  extern "C" {
  void mC_Message_Foreign_RegisterCTopic(
         mC_Itf_Types::SubscriptionAttributesPtr,
         mT_Topic::RegisterTopicParams*,
         char *, mC_Itf_Types::MessageKeyPtr);
  // Combine the attributes and register the topic with the framework
  }
to go with the declaration used by C in mT-Topic.h of
void mC_Message_Foreign_RegisterCTopic(mC_ItfC_SubscriptionAttributesPtr,
                                       mT_Topic_AttributesPtr, char *,
                                       mC_ItfC_MessageKeyPtr);
// Combine the attributes and register the topic with the framework


C++ Component and Topic Discussion

To create an interface between C++ components and the Ada framework, I created a Com3C C++ component along with C++ versions of the Periodic topic and the "Topic-N-to-1 1" topic (that is, the paired "Topic-N-to-1 1 Request" and "Topic-N-to-1 1 Response" topics). 

This included a Component class for C++ component classes to inherit and a mT_Topic class that the various C++ topic classes can inherit.  As yet, nothing has been included in these classes to be inherited since the first goal was to create an interface rather that provide an example of C++ design. 

The Com3C component is an Upon Demand component that has its actions executed by the framework as callbacks when the notifying topic is published by a producer component.  Since this is an example component without a particular reason to be invoked, the Periodic component is used to cause it to be executed when Periodic publishes its periodic topic.  Com3C Install registers to consume this topic so the registered callback (Com3C::Treat_Periodic) is invoked by the framework each time the topic is published. 

This Treat_Periodic method then creates and publishes the "Topic-N-to-1 1 Request" topic with the Com3C::Treat_Response callback to be invoked when the "Topic-N-to-1 1 Response" topic is published.  When this method is invoked it reads and displays the topic data to illustrate that it can do so.  In requesting the read pointer to the topic data, the framework first executes the Com3C::Verify_Response callback similarly to those that can be provided for Ada and C components.  Likewise, before invoking the component specific Verify function, the framework invokes the general mT_Topic_N_to_One_1::Response::Valid function specified by the topic when it was first registered by a component.  These functions also display data to illustrate that they were executed.

Note:  Since there can be Ada, C, and C++ versions of a topic to be used by components written in Ada, C, and C++, only the first topic Verify function to be registered will be invoked by the framework.  Since (currently) App-Install first invokes the Ada component Install procedures that will register the Ada topics of relevance, components of multiple languages to read the same topic will cause the Ada Verify function to be called even though a C++ component is the one invoking the topic read.

C++ note:  The easiest way to supply the callback address in C++ turned out to be to make the callback method static and supply a pointer function in the attributes structure to be passed to the framework.  For instance,
class mT_Topic
{
  ...
  typedef struct // registerTopicParams
  { // input parameters to supply to registerCTopic
    NameType name;      // name of topic
    Int32 id;           // topic identifier
    Int32 size;         // size of topic data area with header
    bool (*validation)(mC_Itf_Types::MessageKeyType); // callback for topic's
                        //  verify function;
                        //  will be ignored if first registered by Ada topic
    Byte permanence;    // retention of queued or not
    Byte storage;       // whether to use reusable buffers
    Byte exchange;      // method of topic exchange
    Byte kind;          // whether request topic or response
    Byte protocol;      // Publish/Subscribe or Point-to-Point
    Byte instances;     // maximum separately maintained instances of Data_Type
                        //  (for indexed Data_Type) - Only 1 accepted currently
    Byte pad1;          // padding to integer boundary
    Byte pad2;
  } RegisterTopicParams; // end struct registerTopicParams

};

class mT_Topic_N_to_One_1 : public mT_Topic
{
  ...
  public:
  class Response
  {
    ...
    static bool Valid( mC_Itf_Types::MessageKeyType Key ); // Access key
    // Validate the Topic Data
    ...
  };

}; // end class mT_Topic_N_to_One_1

  ...
  void mT_Topic_N_to_One_1::Response::Init()
  {
    dataResponse.id = topicIdResponse;
    int i;
    for (i=0; i<30; i++)
    { dataResponse.name[i] = nameResponse[i]; }
    dataResponse.name[29] = ' '; // replace nul by ' '
    dataResponse.size = sizeof(mT_Topic_N_to_One_1::Response::Topic_Type);
    dataResponse.validation = &mT_Topic_N_to_One_1::Response::Valid;
    dataResponse.permanence = (Byte)mC_Itf_Types::Queued;
    dataResponse.storage = (Byte)mC_Itf_Types::Fixed;
    dataResponse.exchange = (Byte)mC_Itf_Types::Request_Response;
    dataResponse.kind = (Byte)mC_Itf_Types::Response;
    dataResponse.protocol = (Byte)mC_Itf_Types::Point_to_Point;
    dataResponse.instances = 1;
  } // end method Init
  ...


C++ Code Examples

Since there are not multiple instances for the use of a C++ topic class or component class, the implementation code has been put in a .cpp file with the class declared in a .hh file.  This works since there is only one call to the Init methods of the topic classes from AppCpp class InitializeCppApp method (via the call sequence began by the call to app_InitializeCpp in the App-Install Ada separate).  The same for the Install method of the components (Com3C::Install in this example) so that there is only one set of keys to be saved.  Of course, this should be changed in the future so that the compiler can store and execute one instance of the code but have multiple instances of the data depending upon how many times the class is instantiated.

mC_Itf_Types.hh

#ifndef MC_ITF_TYPES
#define MC_ITF_TYPES

#include <mC_InfCpp.hh>

class mC_Itf_Types
{

  public:

  enum Buffer_Storage_Allocation_Type
  // Type of storage to use for topic data buffer.  Fixed/Permanent must be
  // used for topics for which the component cannot be notified of a topic
  // update.  If Reusable is used for point-to-point delivery, the buffer will
  // be no longer be assigned after the component returns for the activation
  // that notified it of the updated topic.  Therefore, it cannot access the
  // data later.  The same is true of upon demand delivery except that, since
  // multiple components can register to be notified of the topic update, the
  // buffer continues to be assigned until after all components have returned
  // after being notified.
  { Fixed = 0,    // Buffer is permanent although data may become unusable
    Reusable = 1  // Buffer is temporary and can only be used by point-to-point
  };              // and event driven topics so mC can free the buffer when the
                  // reader is finished (all readers for event driven)

  enum Message_Exchange_Type
  /* Style in which message / instance of topic is to be delivered to /
  --| exchanged with participating components.
  --| Limitations:
  --|   The order of the enumerated literals is important since sub-types are
  --|   declared below that include particular enumerated literals within a
  --|   range.
  --| Notes:
  --|   Content_Filtered requires a producer component that retains a table of
  --|   of the latest content filter criteria from each requesting component
  --|   and special publishing to publish only to those requestors for which
  --|   the data complies with the requestor's criteria.  Such a publishing
  --|   component could be event driven and receive the request topics with the
  --|   criteria in that manner (although, of course, it could miss a request
  --|   since will only receive the most recent instance if multiple requestors
  --|   run before the producer component runs).  However, it is expected that
  --|   it will be Aperiodic so that the requests are queued and can be
  --|   consumed in a read loop before the component does its normal data
  --|   update and determines whether the criteria have been met for the
  --|   various requestors.  A special Publish has to be used to supply the
  --|   destination of each such publish. */
  { No_Exchange = 0,     // only one-way delivery from producer to consumer(s)
    Delivery_Identifier = 1, // delivery only to the consumer that subscribed
                             //  to delivery id of topic instance
    Request_Response = 2,    // synchronous paired topic with a request format
                             //  and a response format
    Content_Filtered = 3 };  // asynchronous paired topic where consumer
                             //  filters the content

  enum Topic_Delivery_Protocol_Type
  // Protocol / pattern to be used to deliver an instance of a topic
  { Publish_Subscribe = 0, // deliver to all components that subscribed as
                           //  consumers
    Point_to_Point = 1 };  // deliver from one component to only one of the
                           //  consumers

  enum Topic_Kind_Type
  // Whether topic is the request or the response.
  { Pub_Sub = 0,    // A publish/subscribe (rather than a point-to-point) topic
    Request = 1,    // Topic is the request to be treated by the consumer
    Response = 2 }; // Topic is the response to be updated by the consumer

  enum Topic_Permanence_Type
  // Whether the persistence of a topic instance is most recently published
  // (until a newer instance is published) or until consumer component has had
  // a opportunity to complete its read of the topic.  EP is for the earliest
  // published the uses the same buffer pointer structures as MRP but returns
  // the oldest instance for a read of the topic.
  { Unknown = 0,  // for initialization
    MRP = 1,      // most recently published
    EP = 2,       // earliest published
    Queued = 3 }; // separate queue for each consuming component

  struct Message_Header_Type
  { // Message header that should be private and not visible except to
    //  allocate space for messages
    Int32 variousData1; // 20 bytes
    Int32 variousData2;
    Int32 variousData3;
    Int32 variousData4;
    Int32 variousData5;
  };
  #define Header_Size 20

  // Pointer to participant key
  struct Participant_Key_Type
  { // Key identifying participant component returned from
    //  registerCComponentParams
    Int32 Value1; // 12 bytes
    Int32 Value2;
    Int32 Value3;
  };
  typedef Participant_Key_Type* ParticipantKeyPtr;

  struct QoService
  { // Quality of Service
    Int32 instances;
    Int32 timeInterval;
    Int32 timeCapacity;
    char  activation; // A=Aperiodic, P=Periodic, U=Upon Demand
  }; // end struct

  #define COMPONENTNAMESIZE 30
  typedef char ComponentNameType[COMPONENTNAMESIZE];

  struct registerComponentParams
  { // input parameters to supply to registerCComponent
    ComponentNameType name;   // name of component
    void (*initialize)(void); // callback for component initialization
    void (*main)(void);       // callback of main method
    Int32   stackSize;        // size for stack; 0 if use standard size
    Address qoS;              // address of Quality of Service info
  };
  typedef registerComponentParams* ComParamsPtr;
  // Pointer to register component parameters

  struct MessageKeyType
  { // Key identifying particular participant component, topic combination
    //  from registerCTopic
    Int32 value1; // 8 bytes - space required to contain component
    Int32 value2; //            registered topic key
  };
  typedef MessageKeyType* MessageKeyPtr;
  // Pointer to message key

  struct SubscriptionAttributesType
  { // component attributes to supply when registering for / subscribing to
    //  a topic
    Participant_Key_Type participant; // participant component key
    Int32 queueSize;     // Queue size to use if topic Permanence is Queued
                         //  and Role is not Producer
    void (*callback)(void); // callback for component upon demand notify
    bool (*verify)(MessageKeyPtr); // callback for particular participant
                         //  component function to verify/filter
                         //  instance of topic prior to allowing the
                         //  Reader to provide a data Ptr.
    Int32 deliveryId;    // To be supplied if registering as a 1-of-N consumer
                         //  for selective delivery
    Int32 instances;     // Number of instances of 1-of-N topics to be retained
                         //  for delivery to consumer
    char detection;      // Whether consumer is notified of new message (N) or
                         //  must poll for it (P)
    char role;           // Whether registering as producer/publisher (P) or
                         //  consumer/subscriber (C)
//  char option;         // Whether registering as the Actual component or
                         //  as Proxy for remote component
//  char duration;       // Whether to endure thru power-glitch, etc
  };
  typedef SubscriptionAttributesType* SubscriptionAttributesPtr;

}; // end class mC_Itf_Types

#endif // MC_ITF_TYPES

mT_Topic.hh

#ifndef MT_TOPIC
#define MT_TOPIC

#include <mC-ItfC.h>
#include <mC_InfCpp.hh>
#include <mC_Itf_Types.hh>

class mT_Topic
{

  public:

  #define TOPICNAMESIZE 30
  typedef char NameType[TOPICNAMESIZE];

  typedef struct // registerTopicParams
  { // input parameters to supply to registerCTopic
    NameType name;       // name of topic
    Int32 id;            // topic identifier
    Int32 size;          // size of topic data area with header
    bool (*validation)(mC_Itf_Types::MessageKeyType); // callback for topic's
                         //  verify function;
                         //  will be ignored if first registered by Ada topic
    Byte permanence;     // retention of queued or not
    Byte storage;        // whether to use reusable buffers
    Byte exchange;       // method of topic exchange
    Byte kind;           // whether request topic or response
    Byte protocol;       // Publish/Subscribe or Point-to-Point
    Byte instances;      // maximum separately maintained instances 
                         //  of Data_Type (for indexed Data_Type) -
                         //  Only 1 accepted currently
    Byte pad1;           // padding to integer boundary
    Byte pad2;
  } RegisterTopicParams; // end struct registerTopicParams

  typedef RegisterTopicParams * AttributesPtr;
  // Pointer to topic register attribute parameters

  typedef struct
  { // input to supply one of a paired topic
    RegisterTopicParams data[2]; // index 0 for Request, 1 for Response
  } RegisterPairedTopicParams;

  void Register(mC_Itf_Types::SubscriptionAttributesPtr subAttributes,
                RegisterTopicParams*, char* status,
                mC_Itf_Types::MessageKeyPtr accessKey);
  // Register the topic

}; // end class mT_Topic

#endif // MT_TOPIC

MessageForeign.hh

#ifndef MESSAGEFOREIGN
#define MESSAGEFOREIGN

#include <mC-ItfC.h>
#include <mC_InfCpp.hh>
#include <mC_Itf_Types.hh>
#include <mT_Topic.hh>

  extern "C" {
  extern void mC_Message_Foreign_RegisterCComponent(mC_Itf_Types::ComParamsPtr,
                char *, mC_Itf_Types::ParticipantKeyPtr);
  // Ada procedure to register a C based component
  }

  extern "C" {
  void mC_Message_Foreign_RegisterCTopic(
         mC_Itf_Types::SubscriptionAttributesPtr,
         mT_Topic::RegisterTopicParams*, char *, mC_Itf_Types::MessageKeyPtr);
  // Combine the attributes and register the topic with the framework
  }

  extern "C" {
  void mC_Message_Foreign_ReadCTopic(Int32, mC_Itf_Types::MessageKeyPtr,
         bool, Address*);
  // Ada procedure to read a topic by a C based component
  }

  extern "C" {
  void mC_Message_Foreign_VerifyCTopic(Int32, mC_Itf_Types::MessageKeyPtr,
         Address*);
  // Ada procedure to read a topic by a C based component
  }

  extern "C" {
  void mC_Message_Foreign_WriteCTopic(Int32, Int32,
         mC_Itf_Types::MessageKeyPtr, mC_Itf_Types::ParticipantKeyPtr,
         Address*);
  // Ada procedure to obtain a write buffer for a topic by a C based component
  }

  extern "C" {
  void mC_Message_Foreign_PublishCTopic(Int32, mC_Itf_Types::MessageKeyPtr);
  // Ada procedure to publish a write buffer for a topic by a C based component
  }

#endif // MESSAGEFOREIGN

AppC++.hh

#ifndef APPCPP
#define APPCPP

#include <com3C.hh>

class AppCpp
{

  public:

    void InitializeCppApp(void); // Initialize C++ App topics and
                                 //  install C++ components

    AppCpp(); // constructor

}; // end class AppCpp

#endif // APPCPP

AppC++.cpp

#include <AppC++.hh>
#include <Com3C.hh>
#include <console.hh>
#include <mT_Topic_N_to_One_1.hh>
#include <mT_Topic_Periodic.hh>

Com3C component3C;
mT_Topic_N_to_One_1 topic_N_to_One_1;
mT_Topic_Periodic topic_Periodic;

void AppCpp::InitializeCppApp(void)
{
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                        "in AppCpp::InitializeCppApp\n");
  console(consoleBuffer,consoleLen);

  topic_N_to_One_1.Init();
  topic_Periodic.Init();
  component3C.Install();

} // end method InitializeCppApp

AppCpp::AppCpp(void)
{
} // end constructor

mT_Topic_Periodic.hh

#ifndef MT_TOPIC_PERIODIC
#define MT_TOPIC_PERIODIC

#include <mT_Topic.hh>
#include <mC_Itf_Types.hh>

class mT_Topic_Periodic : public mT_Topic
{

  public:
  typedef struct
  { // Data type containing the format of the message
    mC_Itf_Types::Participant_Key_Type publishingComponent;
    // Participant key of publishing component
    Int32 referenceNumber;
    // Number that can be changed to check that new value published
    Int32 time;
    // Elapsed time at which sent
  } DataTypeRec; // end struct
  typedef DataTypeRec* DataWriterPtr;
  // Pointer to write the data of the data buffer of the message for the topic
  typedef const DataTypeRec* DataReaderPtr;
  // Pointer to read the data of the data buffer of the message for the topic

  typedef struct
  {
    mC_Itf_Types::Message_Header_Type Header;
    DataTypeRec Data;
  } TopicType;

//-----------------------------------------------------------------------------

  public: void Init();
  // Initialize the internal data

  public: void Register(mC_Itf_Types::SubscriptionAttributesPtr, char*,
                        mC_Itf_Types::MessageKeyPtr);
  // Register the topic

  public: DataReaderPtr Reader(mC_Itf_Types::MessageKeyType, bool);
  // Obtain data pointer to read the topic

  public: DataReaderPtr Verify(mC_Itf_Types::MessageKeyType);
  // Obtain data pointer to verify the topic

}; // end class mT_Topic_Periodic

#endif // MT_TOPIC_PERIODIC

mT_Topic_Periodic.cpp

#include <console.hh>
#include <MessageForeign.hh>
#include <mC_Itf_Types.hh>
#include <mT_Topic.hh>
#include <mT_Topic_Periodic.hh> // "spec" for mT Topic Periodic

// Common data and methods of the mT_Topic_Periodic class

  const Int32 topicId = 105;
  const mT_Topic::NameType Name = "Topic Periodic               "; // with
                                                           // trailing null

  mT_Topic::RegisterTopicParams data; // topic data

  //---------------------------------------------------------------------------

  void mT_Topic_Periodic::Init()
  { // Initialize the topic data
    consoleBufferArray consoleBuffer; consoleLength consoleLen;

    data.id = topicId;

    int i;
    for (i = 0; i < TOPICNAMESIZE; i++)
    { data.name[i] = Name[i];
    } // end for
    data.name[29] = ' '; // replace nul by ' '
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "mT_Topic_Periodic Init %u\n",data.id);
    console(consoleBuffer,consoleLen);

    data.exchange = (Byte)mC_Itf_Types::No_Exchange;
    data.instances = 1;
    data.kind = (Byte)mC_Itf_Types::Pub_Sub;
    data.permanence = (Byte)mC_Itf_Types::MRP;
    data.protocol = (Byte)mC_Itf_Types::Publish_Subscribe;
    data.size = sizeof(mT_Topic_Periodic::TopicType);
    data.storage = (Byte)mC_Itf_Types::Fixed;
    data.validation = 0; // no valid function

  }// end method Init

  //---------------------------------------------------------------------------

  void mT_Topic_Periodic::Register(mC_Itf_Types::SubscriptionAttributesPtr
                                   subAttributes, char* status,
                                   mC_Itf_Types::MessageKeyPtr accessKey)
  { // Register the topic

    mT_Topic::Register(subAttributes, &data, status, accessKey);

  } // end method Register

  //---------------------------------------------------------------------------

  mT_Topic_Periodic::DataReaderPtr mT_Topic_Periodic::Reader(
                                    mC_Itf_Types::MessageKeyType accessKey,
                                    bool freshData)
  // Topic Reader
  {
    consoleBufferArray consoleBuffer; consoleLength consoleLen;

    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "mT_Topic_Periodic Reader %u %u\n",
                          accessKey,&accessKey);
    console(consoleBuffer,consoleLen);
    mT_Topic_Periodic::DataReaderPtr dataAddress; // address of instance of
                                                  //  topic data

    mC_Message_Foreign_ReadCTopic(topicId, &accessKey, freshData,
                                  (Address*)(&dataAddress));
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "mT_Topic_Periodic::Reader %u %u %u \n",
                          accessKey,&accessKey, dataAddress);
    console(consoleBuffer,consoleLen);

    return dataAddress;
  } // end method Reader

  //---------------------------------------------------------------------------

  mT_Topic_Periodic::DataReaderPtr mT_Topic_Periodic::Verify(
                                    mC_Itf_Types::MessageKeyType accessKey)
  // Topic Verify
  {
    consoleBufferArray consoleBuffer; consoleLength consoleLen;

    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "mT_Topic_Periodic Verify %u %u\n",
                          accessKey,&accessKey);
    console(consoleBuffer,consoleLen);
    mT_Topic_Periodic::DataReaderPtr dataAddress; // address of instance of
                                                  //  topic data
    mC_Message_Foreign_VerifyCTopic(topicId, &accessKey,
                                    (Address*)(&dataAddress));
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "mT_Topic_Periodic Verify again %u\n",dataAddress);
    console(consoleBuffer,consoleLen);
    return dataAddress; // (dataReaderPtr)(dataAddress);
  } // end method Verify

// end mT_Topic_Periodic

mT_Topic_N_to_One_1.hh

#ifndef MT_TOPIC_N_TO_ONE_1
#define MT_TOPIC_N_TO_ONE_1

#include <mT_Topic.hh>
#include <mC_Itf_Types.hh>

class mT_Topic_N_to_One_1 : public mT_Topic
{
/*
-- ++
--| Overview:
--|   Service Oriented Command/Response (Point-to-Point N-to-1) topic
--|   declaration to try sending Command/Request of one of N producer
--|   components to the one consumer component to treat and publish a
--|   response.  If registered by the producer component, the notify of
--|   the response will activate the particular producer component that
--|   published the request.
-- --
*/

  protected:

  public:
  class Request
  {
  /* ++
  --| Overview:
  --|   Request topic declaration.
  -- */

    typedef struct  // Data type containing the format of the message
    {
      Int32 Dummy; // Dummy data for request type
      mC_Itf_Types::Participant_Key_Type Source;
      Int32 Ref_No;
      float Time;
    } Data_Type;
    public: typedef Data_Type* DataWriterPtr;
    // Pointer to write the data of the data buffer of the message for topic
    typedef const Data_Type* DataReaderPtr;
    // Pointer to read the data of the data buffer of the message for the topic

    typedef struct
    {
      mC_Itf_Types::Message_Header_Type Header;
      Data_Type Data;
    } Topic_Type;

    //-------------------------------------------------------------------------

    static bool Valid( mC_Itf_Types::MessageKeyType Key ); // Access key
    /*| Validate the Topic Data
    -- ++
    --| Overview:
    --|   This function returns TRUE if Request data passes the validation.
    --| Limitations:
    --|   This function must ONLY be used to validate data following the
    --|   instantiation of a topic Reader.  It must NOT be used after the
    --|   instantiation of a topic Writer since it will overwrite the Valid
    --|   flag of the instantiation parameter causing the lack of the
    --|   assignment of a write buffer pointer to appear to be valid.
    -- */

    public: void Init();

    public: void Register(mC_Itf_Types::SubscriptionAttributesPtr, char*,
                          mC_Itf_Types::MessageKeyPtr);
    // Register the topic

    public: DataReaderPtr Reader(mC_Itf_Types::MessageKeyType, bool);
    // Obtain data pointer to read the topic

    public: DataReaderPtr Verify(mC_Itf_Types::MessageKeyType);
    // Obtain data pointer to verify the topic

    public: DataWriterPtr Writer(mC_Itf_Types::MessageKeyType);
    // Obtain data pointer to write the topic

    public: void Publish(mC_Itf_Types::MessageKeyType);
    // Publish the written topic

  }; // end class Request

  //---------------------------------------------------------------------------

  public:
  class Response
  {
  /* ++
  --| Overview:
  --|   Response topic declaration.
  -- */

  protected:

  public:
    typedef struct
    { // Data type containing the format of the message
      Boolean Success; // Response status
      mC_Itf_Types::Participant_Key_Type Echoed_Source;
      Int32 Echoed_Ref_No;
      float Echoed_Time;
    } Data_Type;
    typedef Data_Type* DataWriterPtr;
    // Pointer to write the data of the data buffer of the message for topic
    typedef const Data_Type* DataReaderPtr;
    // Pointer to read the data of the data buffer of the message for the topic

    typedef struct
    {
      mC_Itf_Types::Message_Header_Type Header;
      Data_Type Data;
    } Topic_Type;

    //-------------------------------------------------------------------------

    static bool Valid( mC_Itf_Types::MessageKeyType Key); // Access key
    /* Validate the Topic Data
    -- ++
    --| Overview:
    --|   This function returns TRUE if Response data passes the validation.
    --| Limitations:
    --|   This function must ONLY be used to validate data following the
    --|   instantiation of a topic Reader.  It must NOT be used after the
    --|   instantiation of a topic Writer since it will overwrite the Valid
    --|   flag of the instantiation parameter causing the lack of the
    --|   assignment of a write buffer pointer to appear to be valid.
    -- */

    public: void Init();

    public: void Register(mC_Itf_Types::SubscriptionAttributesPtr, char*,
                          mC_Itf_Types::MessageKeyPtr);
    // Register the topic

    public: DataReaderPtr Reader(mC_Itf_Types::MessageKeyType, bool);
    // Obtain data pointer to read the topic

    public: DataReaderPtr Verify(mC_Itf_Types::MessageKeyType);
    // Obtain data pointer to verify the topic

    public: DataWriterPtr Writer(mC_Itf_Types::MessageKeyType);
    // Obtain data pointer to write the topic

    public: void Publish(mC_Itf_Types::MessageKeyType);
    // Publish the written topic

  }; // end class Response;

  //---------------------------------------------------------------------------
  // mT_Topic_N_to_One_1 class method declarations

  public: mT_Topic_N_to_One_1();
  public: void Init();

}; // end class mT_Topic_N_to_One_1

#endif // MT_TOPIC_N_TO_ONE_1

Question:  How to return a read pointer in C++ without having to name it as such when invoking either Reader or Verify?  How to prevent whether or not using the const version from being public?  That is, take the choice of data modification out of the hands of the programmer?


mT_Topic_N_to_One_1.cpp

#include <console.hh>
#include <MessageForeign.hh>
#include <mC_Itf_Types.hh>
#include <mT_Topic.hh>
#include <mT_Topic_N_to_One_1.hh>

// Common data and methods of the mT_Topic_N_to_One_1 class.

const Int32 topicIdRequest = 102;
const mT_Topic::NameType nameRequest = "Topic N-to-1 1 Request       ";
                                       // with trailing null
// Notes:  The topic name must end in "Request".

const Int32 topicIdResponse = 103;
const mT_Topic::NameType nameResponse = "Topic N-to-1 1 Response      ";
                                        // with trailing null
// Notes:  The topic name must end in "Response".

mT_Topic topic;
// Instance of mT_Topic class

mT_Topic::RegisterTopicParams dataRequest;
mT_Topic::RegisterTopicParams dataResponse;

//-----------------------------------------------------------------------------
// mT_Topic_N_to_One_1 Request methods

void mT_Topic_N_to_One_1::Request::Init()
{
  dataRequest.id = topicIdRequest;
  int i;
  for (i=0; i<30; i++)
    { dataRequest.name[i] = nameRequest[i]; }
    dataRequest.name[29] = ' '; // replace nul by ' '
    dataRequest.size = sizeof(mT_Topic_N_to_One_1::Request::Topic_Type);
    dataRequest.validation = &mT_Topic_N_to_One_1::Request::Valid;
    dataRequest.permanence = (Byte)mC_Itf_Types::Queued;
    dataRequest.storage = (Byte)mC_Itf_Types::Fixed;
    dataRequest.exchange = (Byte)mC_Itf_Types::Request_Response;
    dataRequest.kind = (Byte)mC_Itf_Types::Request;
    dataRequest.protocol = (Byte)mC_Itf_Types::Point_to_Point;
    dataRequest.instances = 1;
 } // end method Init

//--------------------------------------------------------------------------–

bool mT_Topic_N_to_One_1::Request::Valid(mC_Itf_Types::MessageKeyType Key)
{
  return true;
} // end method Valid

//----------------------------------------------------------------------------

void mT_Topic_N_to_One_1::Request::Register(
                     mC_Itf_Types::SubscriptionAttributesPtr subAttributes,
                     char* status, mC_Itf_Types::MessageKeyPtr accessKey)
{ // Register the topic

  topic.Register(subAttributes, &dataRequest, status, accessKey);

} // end method Register

//----------------------------------------------------------------------------

mT_Topic_N_to_One_1::Request::DataReaderPtr
   mT_Topic_N_to_One_1::Request::Reader(mC_Itf_Types::MessageKeyType accessKey,
                                        bool freshData)
// Topic Reader
{
  mT_Topic_N_to_One_1::Request::DataReaderPtr dataAddress; // address of
                                                 // instance of topic data

  mC_Message_Foreign_ReadCTopic(topicIdRequest, &accessKey, freshData,
                                (Address*)(&dataAddress));

  return dataAddress;

} // end method Reader

//----------------------------------------------------------------------------

mT_Topic_N_to_One_1::Request::DataReaderPtr
   mT_Topic_N_to_One_1::Request::Verify(mC_Itf_Types::MessageKeyType accessKey)
// Topic Verify
{
  mT_Topic_N_to_One_1::Request::DataReaderPtr dataAddress; // address of
                                                  // instance of topic data

  mC_Message_Foreign_VerifyCTopic(topicIdRequest, &accessKey,
                                  (Address*)(&dataAddress));

  return dataAddress;

} // end method Verify

//----------------------------------------------------------------------------

mT_Topic_N_to_One_1::Request::DataWriterPtr
   mT_Topic_N_to_One_1::Request::Writer(mC_Itf_Types::MessageKeyType accessKey)
{ // Topic Writer
  mT_Topic_N_to_One_1::Request::DataWriterPtr dataAddress; // address of
                                                    // instance of topic data

  mC_Message_Foreign_WriteCTopic(topicIdRequest, 0, &accessKey, (Address)(0),
                                  (Address*)(&dataAddress));

  return dataAddress;

} // end method Writer

//----------------------------------------------------------------------------

void mT_Topic_N_to_One_1::Request::Publish(
                                    mC_Itf_Types::MessageKeyType accessKey)
// Topic Publish
{
  mC_Message_Foreign_PublishCTopic(topicIdRequest, &accessKey);
} // end method Publish


//-----------------------------------------------------------------------------
// mT_Topic_N_to_One_1 Response methods

bool mT_Topic_N_to_One_1::Response::Valid(mC_Itf_Types::MessageKeyType Key)
// ++
// Logic_Flow:
//   Validate the data of the response topic.
// --
{
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                        "in mT_Topic_N_to_One_1 Response Valid\n");
  console(consoleBuffer,consoleLen);
  return true;
} // end method Valid

//----------------------------------------------------------------------------

void mT_Topic_N_to_One_1::Response::Init()
{
  dataResponse.id = topicIdResponse;
  int i;
  for (i=0; i<30; i++)
  { dataResponse.name[i] = nameResponse[i]; }
  dataResponse.name[29] = ' '; // replace nul by ' '
  dataResponse.size = sizeof(mT_Topic_N_to_One_1::Response::Topic_Type);
  dataResponse.validation = &mT_Topic_N_to_One_1::Response::Valid;
  dataResponse.permanence = (Byte)mC_Itf_Types::Queued;
  dataResponse.storage = (Byte)mC_Itf_Types::Fixed;
  dataResponse.exchange = (Byte)mC_Itf_Types::Request_Response;
  dataResponse.kind = (Byte)mC_Itf_Types::Response;
  dataResponse.protocol = (Byte)mC_Itf_Types::Point_to_Point;
  dataResponse.instances = 1;
} // end method Init

//----------------------------------------------------------------------------

void mT_Topic_N_to_One_1::Response::Register(
         mC_Itf_Types::SubscriptionAttributesPtr subAttributes, char* status,
         mC_Itf_Types::MessageKeyPtr accessKey)
{ // Register the topic

  topic.Register(subAttributes, &dataResponse, status, accessKey);

} // end method Register

//----------------------------------------------------------------------------

mT_Topic_N_to_One_1::Response::DataReaderPtr
   mT_Topic_N_to_One_1::Response::Reader(
                     mC_Itf_Types::MessageKeyType accessKey, bool freshData)
// Topic Reader
{
  mT_Topic_N_to_One_1::Response::DataReaderPtr dataAddress; // address of
                                               //  instance of topic data

  mC_Message_Foreign_ReadCTopic(topicIdResponse, &accessKey, freshData,
                                 (Address*)(&dataAddress));

  return dataAddress;

} // end method Reader

//----------------------------------------------------------------------------

mT_Topic_N_to_One_1::Response::DataReaderPtr
   mT_Topic_N_to_One_1::Response::Verify
                          (mC_Itf_Types::MessageKeyType accessKey)
// Topic Verify
{
  mT_Topic_N_to_One_1::Response::DataReaderPtr dataAddress; // address of
                                                // instance of topic data

  mC_Message_Foreign_VerifyCTopic(topicIdResponse, &accessKey,
                                   (Address*)(&dataAddress));

  return dataAddress;

} // end method Verify

//----------------------------------------------------------------------------

mT_Topic_N_to_One_1::Response::DataWriterPtr
   mT_Topic_N_to_One_1::Response::Writer(
                               mC_Itf_Types::MessageKeyType accessKey)
{ // Topic Writer
  mT_Topic_N_to_One_1::Response::DataWriterPtr dataAddress; // address of
                                                // instance of topic data

  mC_Message_Foreign_WriteCTopic(topicIdResponse, 0, &accessKey, (Address)(0),
                                  (Address*)(&dataAddress));

  return dataAddress;

} // end method Writer

//----------------------------------------------------------------------------

void mT_Topic_N_to_One_1::Response::Publish(
                                     mC_Itf_Types::MessageKeyType accessKey)
// Topic Publish
{
  mC_Message_Foreign_PublishCTopic(topicIdResponse, &accessKey);
} // end method Publish

//-----------------------------------------------------------------------------
// mT_Topic_N_to_One_1 methods

mT_Topic_N_to_One_1::mT_Topic_N_to_One_1() // constructor
{
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                         "in mT_Topic_N_to_One_1 constructor\n");
  console(consoleBuffer,consoleLen);

//mT_Topic_N_to_One_1::Request request;
//request.Init();

//mT_Topic_N_to_One_1::Response response;
//response.Init();

} // end constructor

void mT_Topic_N_to_One_1::Init()
{
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                         "in mT_Topic_N_to_One_1 Init\n");
  console(consoleBuffer,consoleLen);

  mT_Topic_N_to_One_1::Request request;
  request.Init();

  mT_Topic_N_to_One_1::Response response;
  response.Init();

} // end method Init

Com3C.hh

#ifndef COM3C
#define COM3C

#include <Component.hh>
#include <mC-ItfC.h>
#include <mC_Itf_Types.hh>

class Com3C : public Component
{
  public:

    Com3C();

    void Install(void);

    static void Treat_Response(void);

    static bool Verify_Response(mC_Itf_Types::MessageKeyPtr);

    static void Treat_Periodic(void);

}; // end class Com3C

#endif // COM3C

Com3C.cpp

#include <Com3C.hh>
#include <console.hh>
#include <mC_Itf_Types.hh>
#include <mT_Topic_N_to_One_1.hh>
#include <mT_Topic_Periodic.hh>
#include <MessageForeign.hh>
#include <string.h>

// Objects and methods of C++ component.
// Note: There is only one instance of the Com3C class.

mC_Itf_Types::Participant_Key_Type comC3_Key;
mC_Itf_Types::MessageKeyType comC3_N_to_1_Request_Key;
mC_Itf_Types::MessageKeyType comC3_N_to_1_Response_Key;
mC_Itf_Types::MessageKeyType comC3_Periodic_Key;

Int32 comC3_Request_Ref_No;

//-----------------------------------------------------------------------------

void Com3C::Treat_Periodic(void)
{ // Treat Topic_Periodic event
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                         "in Com3C::Treat_Periodic\n");
  console(consoleBuffer,consoleLen);

  // Obtain Topic N_to_One_1 Request write buffer.
  mT_Topic_N_to_One_1::Request request;
  mT_Topic_N_to_One_1::Request::DataWriterPtr
        dataRequest = request.Writer(comC3_N_to_1_Request_Key);
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                        "Com3C::Treat_Periodic after Request Writer %u\n",
                        dataRequest);
  console(consoleBuffer,consoleLen);

  if (dataRequest == 0)
  { // no data buffer available for topic
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                   "Com3C::Treat_Periodic Request no data buffer for topic\n");
    console(consoleBuffer,consoleLen);
  }
  else
  { // Write data into data buffer
    dataRequest->Dummy = 10;
    dataRequest->Source = comC3_Key;
    comC3_Request_Ref_No++;
    dataRequest->Ref_No = comC3_Request_Ref_No;
    dataRequest->Time = 10.2;
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
        "Com3C::Treat_Periodic Request Source %u %u %u\n",
        dataRequest->Source.Value1, dataRequest->Source.Value2,
        dataRequest->Source.Value3 );
    console(consoleBuffer,consoleLen);
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
        "Com3C::Treat_Periodic Request Ref_No %u\n",
        dataRequest->Ref_No );
    console(consoleBuffer,consoleLen);

    // Publish Topic N_to_One_1 Request.
    request.Publish(comC3_N_to_1_Request_Key);
  }

} // end method Treat_Periodic

//-----------------------------------------------------------------------------

void Com3C::Treat_Response(void)
{ // Treat Response to N_to_One_1 Request
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
      "in Com3C::Treat_Response\n");
  console(consoleBuffer,consoleLen);

  // Obtain read-only pointer to data to be read.
  mT_Topic_N_to_One_1::Response response;
  mT_Topic_N_to_One_1::Response::DataReaderPtr
          dataResponse = response.Reader(comC3_N_to_1_Response_Key, true);
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                 "comC3::Treat_Response after Reader %u\n", \
                 dataResponse);
  console(consoleBuffer,consoleLen);

  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                 "Response publishing component %u %u %u\n", \
                  dataResponse->Echoed_Source.Value1,
                  dataResponse->Echoed_Source.Value2, \
                  dataResponse->Echoed_Source.Value3);
  console(consoleBuffer,consoleLen);
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                  "Response reference number & time %u %f\n",
                  dataResponse->Echoed_Ref_No,dataResponse->Echoed_Time);
  console(consoleBuffer,consoleLen);
 // dataResponse->Echoed_Source.Value1 = 55; // attempt to change value

} // end method Treat_Response

//-----------------------------------------------------------------------------

bool Com3C::Verify_Response(mC_Itf_Types::MessageKeyPtr accessPtr)
{ // Verify Response to N_to_One_1 Request
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                         "in Com3C::Verify_Response\n");
  console(consoleBuffer,consoleLen);

  mC_Itf_Types::MessageKeyType key;   // copy key via
  memcpy(&key,accessPtr,sizeof(key)); //  supplied pointer

  // Obtain read-only pointer to data to be verified.
  mT_Topic_N_to_One_1::Response response;
  mT_Topic_N_to_One_1::Response::DataReaderPtr
                            dataResponse = response.Verify(key);
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                 "comC3::Verify_Response after Verify %u\n", \
                 dataResponse);
  console(consoleBuffer,consoleLen);

  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                  "Verify publishing component %u %u %u\n", \
                  dataResponse->Echoed_Source.Value1,
                  dataResponse->Echoed_Source.Value2, \
                  dataResponse->Echoed_Source.Value3);
  console(consoleBuffer,consoleLen);
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                  "Verify reference number & time %u %f\n",
                  dataResponse->Echoed_Ref_No,dataResponse->Echoed_Time);
  console(consoleBuffer,consoleLen);
 // dataResponse->Echoed_Source.Value1 = 55; // attempt to change value
  return true; // as if verified the data
} // end method Treat_Verify

//-----------------------------------------------------------------------------

void Com3C::Install(void)
{
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,"in Com3C::Install\n");
  console(consoleBuffer,consoleLen);

  // Initialize
  comC3_Request_Ref_No = 0;

  // Setup to register the component with the framework.
  mC_Itf_Types::registerComponentParams params;
  mC_Itf_Types::QoService qoS;

  qoS.activation = 'U';   // upon demand
  qoS.instances = 1;
  qoS.timeInterval = 500; // milliseconds
  qoS.timeCapacity = 2;   // milliseconds

  int i;                      // set component name to "comC3"
  for (i = 0; i < 30; i++)
  { params.name[i] = ' ';
  }
  params.name[0] = 'c';
  params.name[1] = 'o';
  params.name[2] = 'm';
  params.name[3] = 'C';
  params.name[4] = '3';
  params.initialize = 0;          // no Initialize method
  params.main = 0;                // no Main method callback
  params.stackSize = 0;           // use default
  params.qoS = (Address)(&qoS);   // address of quality of service

  // Declare the variables to be set by the framework -
  //  key must be used to register the topics
  char status;

  // Register the component
  mC_Message_Foreign_RegisterCComponent( &params, &status, &comC3_Key );

  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                "returned to comC3-Install again %c %u %u %u\n",
                status,comC3_Key.Value1,comC3_Key.Value2,comC3_Key.Value3);
  console(consoleBuffer,consoleLen);

  if ( (status == 'V') || (status == 'v') )
  { // component registered successfully

    // Setup to register the mT_Topic_N_to_One_1 Request and Response topics
    // with the framework so as to publish the request and consume the
    // response by this component.
    // Note:
    //   The component that consumes the request is located in a
    //   remote application.
    mC_Itf_Types::SubscriptionAttributesType subscriptionParams;

    subscriptionParams.participant = comC3_Key; // participant component key
    subscriptionParams.queueSize = 0;     // Queue size to use if topic
                                          //  Permanence is Queued and Role
                                          //  is not Producer
    subscriptionParams.callback = 0;      // null - publishing the
    subscriptionParams.verify = 0;        // null     request
    subscriptionParams.deliveryId = 0;    // To be supplied if registering as a
                                          //  1-of-N consumer for selective
                                          //  delivery
    subscriptionParams.instances = 0;     // Number of instances of 1-of-N
                                          //  topics to be retained for
                                          //  delivery to consumer
    subscriptionParams.detection = 'N';   // Upon Demand to be notified of new
                                          //  instance of topic
    subscriptionParams.role = 'P';        // registering as producer/publisher

    // Register for the N-to-1 Request topic.
    mT_Topic_N_to_One_1::Request request;
    request.Register(&subscriptionParams, &status, &comC3_N_to_1_Request_Key);

    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "comC3::Install %c %u\n",
                          status,comC3_N_to_1_Request_Key);
    console(consoleBuffer,consoleLen);

    // Register to send N-to-1 Response topic.
    // Notes:
    //   Only need to change the subscription params that are to be different
    //   from those set for the previous register of a topic.
    subscriptionParams.callback = &Com3C::Treat_Response;// callback for notify
    subscriptionParams.verify = &Com3C::Verify_Response; // callback for verify
    subscriptionParams.role = 'C'; // registering as consumer

    // Register for the N-to-1 Response topic.
    mT_Topic_N_to_One_1::Response response;
    response.Register(&subscriptionParams,&status,&comC3_N_to_1_Response_Key);
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "comC3::Install %c %u\n",
                          status,comC3_N_to_1_Response_Key);
    console(consoleBuffer,consoleLen);

    // Register to be notified of Topic Periodic event
    subscriptionParams.callback = &Com3C::Treat_Periodic;
    subscriptionParams.verify = 0;  // null verify
    subscriptionParams.role = 'C';  // registering as consumer

    mT_Topic_Periodic periodic;
    periodic.Register( &subscriptionParams, &status, &comC3_Periodic_Key );
    consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,
                          "comC3::Install %c %u\n",
                          status,comC3_Periodic_Key);
    console(consoleBuffer,consoleLen);

  } // end if for successful component register

} // end method Install

//-----------------------------------------------------------------------------

Com3C::Com3C()
{ // constructor
  consoleBufferArray consoleBuffer; consoleLength consoleLen;
  consoleLen = snprintf(consoleBuffer,CONSOLE_MAX,"in Com3C::Com3C\n");
  console(consoleBuffer,consoleLen);
} // end constructor





GNU GPS mostly compiled C++ files included in the GPS project.  However, the build didn't complete since it would flag various "errors" that didn't occur when the files were compiled using the g++ executable using a batch file.

Then, when I moved the updated application source files from one PC back to another the build failed.  Perhaps I was using a different project file in GPS.  In any case I had to add numerous C files to the batch file to get a working link; that is, one where the unit was known to the linker.  In addition, I had to have two versions of the Console header since the one needed for C++
  extern "C" { extern void console(char *, Int32); }
to interface with the Ada pragma Import resulted in compile errors in the build for the .c files.  This happened even though the similar extern declarations for the Foreign Ada package Imports did not result in a problem.  Therefore, I provided two headers, console.h and console.hh with the first included in the C code files and the second included in the C++ code files.  The console.h file has the declaration
  extern void console(char *, Int32);

The GPS project is App3C.  As before, the indented lines in the following .bat file are really part of the previous non-indented line.

cd C:\Source\EP\ObjectC
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  -IC:\Source\EP\Util -IC:\Win32Ada\src -aLC:\Source\EP\ObjectC
  C:\Source\EP\UserApp\Try7\AppC\com_periodic.adb
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\Util -IC:\Win32Ada\src
  -aLC:\Source\EP\ObjectC C:\Source\EP\UserApp\Try7\mT-Topic_Periodic.adb
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\Util -IC:\Win32Ada\src
  -aLC:\Source\EP\ObjectC C:\Source\EP\UserApp\Try7\mT-Topic_N_to_One_1.adb
c:\gnat\2011\bin\ar rc libapp3C.a com_periodic.o mT-Topic_Periodic.o
  mT-Topic_N_to_One_1.o
cd C:\Source\EP\UserApp\Try7
c:\gnat\2011\bin\gnatmake -c -aLC:\Source\EP\ObjectC -PApp3C.gpr
c:\gnat\2011\bin\g++ -c C:\Source\EP\UserApp\Try7\mC-ItfC.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 C:\Source\EP\UserApp\Try7\console.h
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 C:\Source\EP\UserApp\Try7\console.hh
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\AppC\app-InitializeAda.c
  -o C:\Source\EP\ObjectC\app-InitializeAda.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 C:\Source\EP\UserApp\Try7\mT-Topic.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 C:\Source\EP\UserApp\Try7\mT-Topic.c
  -o C:\Source\EP\ObjectC\mT-Topic.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\mT-TopicNto1.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\mT-TopicNto1.c -o C:\Source\EP\ObjectC\mT-TopicNto1.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\mT-Topic1ofN.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\mT-Topic1ofN.c -o C:\Source\EP\ObjectC\mT-Topic1ofN.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\mT-TopicPeriodic.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  -IC:\Source\EP\UserApp\Try7\AppC C:\Source\EP\UserApp\Try7\AppC\mT-TopicPeriodic.c
  -o C:\Source\EP\ObjectC\mT-TopicPeriodic.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\mT-TopicContentFiltered.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC C:\Source\EP\UserApp\Try7\mT-TopicContentFiltered.c
  -o C:\Source\EP\ObjectC\mT-TopicContentFiltered.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\AppC\comC1.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  -IC:\Source\EP\UserApp\Try7\AppC C:\Source\EP\UserApp\Try7\AppC\comC1-Install.c
  -o C:\Source\EP\ObjectC\comC1-Install.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7
  -IC:\Source\EP\UserApp\Try7\AppC C:\Source\EP\UserApp\Try7\AppC\comC1-Main.c
  -o C:\Source\EP\ObjectC\comC1-Main.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC1-Verify-mT-TopicNto1-Response.c
  -o C:\Source\EP\ObjectC\comC1-Verify-mT-TopicNto1-Response.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC1-Verify-mT-TopicPeriodic.c
  -o C:\Source\EP\ObjectC\comC1-Verify-mT-TopicPeriodic.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC2.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC2-Install.c -o C:\Source\EP\ObjectC\comC2-Install.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC2-1ofN.c -o C:\Source\EP\ObjectC\comC2-1ofN.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC2-Nto1-Request.c
  -o C:\Source\EP\ObjectC\comC2-Nto1-Request.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC2-Verify-mT-TopicNto1-Request.c
  -o C:\Source\EP\ObjectC\comC2-Verify-mT-TopicNto1-Request.o
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\comC2-ContentFiltered-Response.c
  -o C:\Source\EP\ObjectC\comC2-ContentFiltered-Response.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\AppC\component.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\component.cpp -o C:\Source\EP\ObjectC\component.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\com3C.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7
  C:\Source\EP\UserApp\Try7\AppC\comC1.h
c:\gnat\2011\bin\gcc -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\app-InitializeC.c
  -o C:\Source\EP\ObjectC\app-InitializeC.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\appC++.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\appC++.cpp -o C:\Source\EP\ObjectC\appC++.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\app-InitializeCpp.c
  -o C:\Source\EP\ObjectC\app-InitializeCpp.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\Com3C.cpp -o C:\Source\EP\ObjectC\Com3C.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\MessageForeign.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\mT_Topic.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\mT_Topic.cpp -o C:\Source\EP\ObjectC\mT_Topic.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\mT_Topic_N_to_One_1.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\mT_Topic_N_to_One_1.cpp
  -o C:\Source\EP\ObjectC\mT_Topic_N_to_One_1.o
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\mT_Topic_Periodic.hh
c:\gnat\2011\bin\g++ -c -IC:\Source\EP\UserApp\Try7 -IC:\Source\EP\UserApp\Try7\AppC
  C:\Source\EP\UserApp\Try7\AppC\mT_Topic_Periodic.cpp
  -o C:\Source\EP\ObjectC\mT_Topic_Periodic.o
cd C:\Source\EP\ObjectC
c:\gnat\2011\bin\ar rc libapp3C.a app-InitializeC.o app-InitializeCpp.o
  app-InitializeAda.o
c:\gnat\2011\bin\ar rc libapp3C.a mT-Topic.o mT-Topic1ofN.o mT-TopicNto1.o
  mT-TopicPeriodic.o mT-TopicContentFiltered.o
c:\gnat\2011\bin\ar rc libapp3C.a comC1-Install.o comC1-Main.o
  comC1-Verify-mT-TopicNto1-Response.o comC1-Verify-mT-TopicPeriodic.o
c:\gnat\2011\bin\ar rc libapp3C.a comC2-Install.o comC2-Nto1-Request.o
  comC2-Verify-mT-TopicNto1-Request.o comC2-ContentFiltered-Response.o comC2-1ofN.o
c:\gnat\2011\bin\ar rc libapp3C.a appC++.o Com3C.o component.o mT_Topic.o
  mT_Topic_N_to_One_1.o mT_Topic_Periodic.o
c:\gnat\2011\bin\gnatbind -x App3.ali
c:\gnat\2011\bin\gnatlink App3.ali libapp3C.a -o App3C.exe
cd C:\Source\EP\UserApp\Try7\AppC
pause


Run results for App3C while App1 is also running

The consumer of the "Topic-N-to-1 1" topic (the Ada version is contained in the mT-Topic_N_to_One_1 .ads and .adb files while the C++ version is in the mT_Topic_N_to_One_1 .hh and .cpp files) is in an App1 component.  Therefore, the framework of the App3C application has to forward the Request to that of App1 that, in turn, forwards it to the consumer component.  It produces and publishes the Response to the framework that forwards it to the requesting application (that is, App3C) that, in turn, causes the Com3C::Treat_Response callback to be executed as will be pointed out in the .log file below.  The other results are the same as in the previous post since they are for the Ada Periodic producer component and the C ComC1 and ComC2 components.

Since there are few threads available in Windows, the framework assigns most of the components to the same thread priority.  This causes round robin time sharing such that Windows causes a context switch from one concurrent active thread to another.  Therefore, the console output in the log contains output from one method and then a different one and then from the first again on many different occasions. 

a) Ada component thread that publishes Periodic topic
b) Com3C C++ component thread
c) comC1 C component thread
d) framework threads

...
in app_InitializeCpp                   ç App-Install invokes app_InitializeCpp
in AppCpp::InitializeCppApp
in mT_Topic_N_to_One_1 Init            ç Init method of the
mT_Topic_Periodic Init 105                 two C++ topics
in Com3C::Install                      ç Entry to C++ component Install method
in mC-Message-Foreign-Register_Component
comC3                                  ç beginning of comC3 Install
Init 0                                     no Initialize or Main
Main 0                                     callback for component
...
returned to comC3-Install again V 3 9 0 ç Valid Register, key of 3,9,0
...
comC3::Install S 1                     ç Success for register of last topic 
Do Finalize                            ç end of all the Installs
...
Com_Periodic to publish Topic_1 1 2 3 1 5757 ç Ada Periodic topic published
Com_Periodic exit Main
in Com3C::Treat_Periodic            ç this causes Com3C callback to be invoked
In comC1-Main 1 4990624                 and periodic comC1 "C" Main to be
                                        invoked for first time
Topic_Writer Queued 9 9 Topic N-to-1 1 Request ç Com3C gets N-to-One 1 writer    
mT_TopicPeriodic_Reader 1 4990624   ç comC1 Main reads Periodic topic
Com3C::Treat_Periodic after Request Writer 499560
in comC1_Verify_mT_TopicPeriodic
Com3C::Treat_Periodic Request Source 3 9 0 ç Com3C to do Request for 3,9,0
mT_TopicPeriodic_Verify 1 4990624     ç comC1 thread
Com3C::Treat_Periodic Request Ref_No 1     ç   with reference number of 1
Foreign Verify Access_Key 271055872
MS_Pipe Transmit SENT Topic 3to1 1 9 24    ç N-to-One 1 Request sent to App1
mT_TopicPeriodic_Verify again 4996532 ç comC1 thread again
comC1_Verify_mT_TopicPeriodic after Verify 499653
publishing component 1 2 3            ç ComC1 verify of periodic topic
reference number & time 1 5757             examines the data
mT_TopicPeriodic_Reader 1 4990624 271056400
comC1Main after Read 4996532
Topic Message received 10 24 1                      ç N-to-One 1 Response
publishing component 1 2 3            ç ComC1 reader examines
MS_Topic received  1      0  1  1 \\.\pipe\app 1to3 ç   received from App1
reference number & time 1 5757        ç   the data
in Com3C::Treat_Response                   ç Com3C callback to treat
                                                response invoked
mTTopicNto1ResponseReader 1818326017 4991584
in mT_Topic_N_to_One_1 Response Valid      ç topic's Valid callback invoked
mTTopicNto1ResponseReader 1818326017 4991584 2710
in Com3C::Verify_Response                  ç Com3C Verify callback invoked
comC1-Main after Response Read 0      ç ComC2 yet to run to
Foreign Verify Access_Key 304610276
comC1-Main no data for response topic ç   produce response for comC1
comC3::Verify_Response after Verify 4996244
mTTopicNto1RequestWriter 1818326017 4991040
Verify publishing component 3 9 0          ç Com3C verify callback of topic
Topic_Writer Queued 7 7 Topic Nto1 Request                     
Verify reference number & time 1 10.200000 ç   from 3,9,0 with ref number 1
mTTopicNto1RequestWriter again 4991156
comC3::Treat_Response after Reader 4996244 ç return to Com3C from Reader
comC1-Main after Request Writer 4991156
Response publishing component 3 9 0        ç   echoing 3,9,0 as publisher
comC1-Main to publish Request 1 43240 12
Response reference number & time 1 10.200000 ç and 1 as reference number
...