Showing posts with label GPS. Show all posts
Showing posts with label GPS. Show all posts

Tuesday, November 8, 2011

Restructuring of Framework Remote Component


Restructuring of Framework Remote Component

 Now that the treatment of the message protocol for communications between the user applications and the display application had been incorporated into the mC framework it became time to restructure the Remote Component to treat the interface to the Display application using the same Ada packages and methods as those for other User applications. 

This took me longer than expected and is not yet finished.  Mostly however because some features were also added that are not strictly related to employing the user application Remote methods in common with the display interface to avoid the duplication that occurred when the cloned user display components were moved into the framework Remote component.  Four of these were

   1) to get application App3 that contains C and C++ user components up-to-date after having been ignored for quite some time while a number of framework changes were being made.
   2) to use Windows interfaces to check which of the other applications of the configuration of the current PC are running,
   3) to use Windows to do the same for a different PC in the configuration,  and
   4) to send a Remote Register Complete topic between running user applications to indicate to a connected application that the sending application has completed its Remote Registration with the receiving application.  Sometime in the future this can be used to avoid transmitting other topics until the sending application is able to determine that the connected application has completed its remote registration with the sending application and hence is ready to treat remote topics.

Another feature to be added will be to monitor the communications between the user application and the display application to check that the two applications remain connected or, if become reconnected, to continue as best as possible from where communications was lost.  Yet another (structure only change) will be to package the remote registration procedures into a Registration unit for easier recognition of their common rationale.

An unrelated additional feature will be to have the first running application of the configuration launch the others.

As part of this change, the configuration file was changed to have a user applications portion and a display applications portion so that one such file can be used both by the user application framework and by the display application.  The user application framework needed this change as part of incorporating the treatment of the display interface via the same methods as the user applications.

While making these changes an error was detected where the application identifier was treated (in various places) as an index into arrays of data concerning applications of the configuration and connected applications.  This previously had not become apparent since the debug cases had been for user applications 1, 2, and 3.  When I added the display application for common treatment, I separated the possible values for the identifiers into one range values for user applications and another range for display applications.  Thus the display application came to be assigned an identifier of 15 while the arrays were sized as 1 to 5 so that a direct index of the identifier could no longer be used.  Further, I could find this sort of thing better if I switched app 2, for instance, to app 5 to have gaps in the user app identifiers which I will need to do.
Above is a figure showing how the user Display components were previously moved into a common framework Display component. 

The following second figure illustrates how the Display interface now uses the same Methods as the user components and how, in the future, it will use the same communications Monitor package and package the remote registration into its own unit.
The new diagram is meant to show that the Remote Component with its thread (the top middle oval to indicate the thread – enclosed icon to indicate the Ada package) includes inputs from and outputs to the tables and reads the Transmit, Receive and Watch Queues upon receiving a wakeup event (that is, the notify of a dataless topic that is published as part of adding the entry to the queue).

The Transmit Queue is written via the publish of a topic from various components while the Receive Queue is written to contain messages received from other applications including the Display App via the receive ports of the MS_Pipe and WinSock communication methods that each have a thread that blocks to wait for a new message from its associated application. 

Received display messages are passed to the Display subpackage that converts them to instances of the Display Event Request topic message and then publishes them for distribution.  In this case the Remote component also queues to the Transmit Queue. 

A received Display Event Response topic (dequeued from the Receive Queue) as well as an unsolicited Display Command topic message are treated via Display as received by the framework (while running under the publishing component's thread).  The Display package supplies the Display protocol header in place of that of the Topic protocol and transmits to the display app via the selected Remote Method.

Hence the Display package is the Display Protocol to Topic Protocol converter and vice versa.  This design, as mentioned in the previous post, allows for the use of other protocols to be added; such as an A661 Protocol.  Only another protocol converter need be added, just as can be done for communication methods, by adding another supported method to be selected by the Method package.  When this becomes necessary a protocol selector package should be added to invoke callback procedures of the particular converter package as is done by Method to select those of MS_Pipe or WinSock.  Other communication drivers can, of course, be added as well where Method would then also contain callback procedure entries to the new method.

Monitor / Registration

The Monitor package will be discussed after monitoring of the user-display application traffic has been implemented.  The Registration package will just be grouping the remote register procedures within such a package. 

Windows Interface to Detect Running Applications

There are supposed to be newer Windows interfaces to return whether a particular process (that is, application) is running on the current PC or on a named one.  Others to start a process on the current PC. 

Since these interfaces don't seem to be available via the GNAT libraries (and certainly not via Win32Ada that contains interfaces to much older versions of Windows), I attempted to access them through a Visual C++ function and link it via gnatlink with the rest of exploratory project.  After various attempts I put that aside to return to later.

I can, however, detect if a specific application is currently running via the Windows interfaces provided with GNAT and Win32Ada.
  BOOL WINAPI EnumProcessModules
  ( __in   HANDLE hProcess,
    __out  HMODULE *lphModule,
    __in   DWORD cb,
    __out  LPDWORD lpcbNeeded
  );
can be used.  To do this, the appRunningC.c function was created and imported to Ada via
  pragma Import(C, App_Running, "appRunningC");

The Ada declaration used was
  function App_Running
  ( Application : in Interfaces.C.Strings.Chars_Ptr
  ) return Interfaces.C.char;
where the Chars_Ptr is used to point to a null terminated character array containing the name of the application along with its path as obtained from the Apps-Configuration.dat file.  The returned character is typecast to a byte value to indicate whether the application is running or not.

The code of appRunningC is
#include <mC-ItfC.h>
#include <ctype.h>
#include <psapi.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>
#include <windows.h>


// Microsoft Help comment:
//   To ensure correct resolution of symbols, add Psapi.lib to TARGETLIBS
//   and compile with -DPSAPI_VERSION=1
// My comment:
//   For GNAT, include C:\GNAT\2011\lib\gcc\i686-pc-mingw32\4.5.3\libpsapi.a
//   in the gnatlink command. 


void strConvert( char * inStr, char * outStr )
{ // Convert string to all lower case while switching any forward slash
  // in pathname to a backward slash
  int i = 0;
  while (inStr[i] != 0)
  {
     if (inStr[i] == '/')
     { outStr[i] = '\\';
     }
     else
     { outStr[i] = tolower(inStr[i]);
     }
     i++;
  } // end loop
  outStr[i] = 0; // attach trailing null


} // end method strConvert 


int MatchModulePathname( DWORD processID, char * Application )
   { // Check application name at beginning of module list for process for match.


    HMODULE hMods[1024];
    HANDLE hProcess;
    DWORD cbNeeded;
    unsigned int i;


    // Get a handle to the process (that is, application).
    hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
                            PROCESS_VM_READ,
                            FALSE, processID );
    if (NULL == hProcess)
        return 0; // false


    // Get a list of all the modules in this process.
    if ( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded) )
    {


        // Only the first name will contain the application name of the process.
        TCHAR szModName[MAX_PATH], ModName[MAX_PATH];


        // Get the full path to the module's file.
        if ( GetModuleFileNameEx( hProcess, hMods[0], szModName,
             sizeof(szModName) / sizeof(TCHAR)) )
        {
            strConvert( szModName, ModName );


            // Check if module name with path matches that of the Application.
            if (strcmp(Application,ModName) == 0)
            {
               // Release the handle to the process and return found.
               CloseHandle( hProcess );
               return 1; // true
            }
        }


    } // end if ( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded) )


    // Release the handle to the process.
    CloseHandle( hProcess );
    return 0; // false


} // end method MatchModulePathname


extern "C" char appRunningC(char * Application )
{ // Determine if Application is running.
    DWORD aProcesses[1024];
    DWORD cbNeeded;
    DWORD cProcesses;
       unsigned int i;


    // Get the list of process identifiers.
    if ( !EnumProcesses( aProcesses, sizeof(aProcesses), &cbNeeded ) )
        return 2; // Application cannot be found due to problem


    // Calculate how many process identifiers were returned.
    cProcesses = cbNeeded / sizeof(DWORD);


    // Examine module names for each process for match to input.
    char AppPath[MAX_PATH];
        strConvert(Application, AppPath);
         for ( i = 0; i < cProcesses; i++ )
         {
            if (MatchModulePathname( aProcesses[i], AppPath ) == 1)
            {
                return 1; // Application found
            }
        }


    return 0; // Application not found


} // end method appRunningC

This routine is currently being used to check whether each application of the configuration (other than the application that is doing the checking) is running.  This can be changed to pass a list of all of the other applications in the configuration to appRunningC and return an array of those that are running to avoid multiple calls to the OpenProcess and EnumProcessModules functions.

GNAT Compiler

While making the various changes it seemed that GNAT GPS no longer rebuilt changed separates.  This seemed to be the case after the addition of the C function for use by the Ada framework Remote-Method-MS_Pipe package to interface to Windows to check what applications of the configuration were running.  Therefore I had to start compiling the packages that I changed with statements such as
c:\gnat\2011\bin\g++ -c -g -IC:\Source\EP\UserApp\Try10 -IC:\Source\EP\Util
  -IC:\Win32Ada\src -aLC:\Source\EP\ObjectC
  C:\Source\EP\UserApp\Try10\mc-message-remote.adb -o mc-message-remote.o
in a batch file (where the indented lines are actually part of the first line) as well as the .c file.  The -g switch includes debug symbols in the .o object file to be included in the eventual .exe file by gnatlink.

Remote Register Complete topic

The implementation of the Remote Register Complete topic took longer than expected.  This topic is both produced and consumed by the Remote framework component.  However, the instance produced by the Remote component of one application is meant for that of another application. 

Therefore the topic used the recently added Requested Delivery method of message exchange so each application could register to consume a delivery identifier that equaled its application identifier.  The Remote component of the publishing application supplies the delivery identifier of the application to receive the topic as it publishes the topic.  Therefore there are as many possible publishers of the topic as there are applications and the same number of consumers.

This is as the message exchange delivery method was intended to treat.  The difference in this case was that the same component was both a publisher and a consumer so its Role was Either.  Since this Role hadn't been previously used, this caused a few problems that had to be tracked down and corrected.  However, another problem caused confusion in identifying what problems were caused by this new role.

That was due to one application of a pair seeming to transmit its instance of the topic to the other application and that application seeming to create its instance but not doing the transmit.  Finally (I must be getting old) I identified the reason.

The registering of a delivery identifier to be consumed involves, as has been done in the past, two variables where the second one is referenced in the Register call.  The first of these is an array of identifier pairs indicating five possible pairs of delivery identifiers that indicate the identifiers the component is to treat.  Each pair indicates a range of values where the second entry can be 0 to indicate that there is no range; only the particular identifier of the first entry.  The second variable contains the count of the number of pairs to examine and the doubly indexed array of values.  Normally, of course, the count will be one.

Registering to consume the Remote Register Complete topic, the Remote Install procedure declared
    Delivery_Id_List
    --| Treat all "Remote Register Complete Topic" messages with ids of the app
    : mC.Itf_Types.Delivery_Id_Array_Type
    := ( ( 1, 1 ), ( 0, 0 ), ( 0, 0 ), ( 0, 0 ), ( 0, 0 ) );
    Delivery_Id
    --| Deliver topic when identifier is that of local app
    : mC.Itf_Types.Delivery_List_Type
    := ( Count => 1,
         List  => Delivery_Id_List );
mimicking what had been done in the past for other Requested Delivery and Delivery Identifier delivery methods.  Except in those cases, the Delivery_Id_List object was declared as constant since the identifiers were known at compile-time. 

In this case, since the pair of delivery ids depends upon the application's own identifier – that isn't known until initialization-time, the value was initialized as shown above and then modified just prior to the Register call to contain the running application's id as shown below.


  Delivery_Id_List := ( ( Integer(Local_App.Id), Integer(Local_App.Id) ),
                        ( 0, 0 ), ( 0, 0 ), ( 0, 0 ), ( 0, 0 ) );


  mT.Remote_Register_Complete_Topic.Request.Data.Register
  ( Participant => Component_Main_Key,
    Detection   => mC.Itf_Types.Event_Driven,
    Role        => mC.Itf_Types.Either,
    Delivery_Id => Delivery_Id,
    Callback    => Monitor.Treat_Register_Complete'access,
    Access_Key  => Remote_Register_Complete_Topic_Access_Key,
    Status      => Data_Status );
where the Count in the Delivery_Id variable remains as 1.

Since this kind of Register (other than the use of Either for the Role instead of Consumer) had been working on the order of a year or more it didn't occur to me that this late resetting of the Delivery_Id_List could be causing any problems. 

However, I finally determined that the compiler was ignoring the resetting of the value to be used by Delivery_Id in the object code that it generated.  So both applications of the pair were specifying that they would consume delivery id 1.  I changed the source code to


  declare


    Delivery_Id_List
    --| Treat all "Remote Register Complete Topic" messages with ids of the app
    : mC.Itf_Types.Delivery_Id_Array_Type
    := ( ( Integer(Local_App.Id), Integer(Local_App.Id) ),
         ( 0, 0 ), ( 0, 0 ), ( 0, 0 ), ( 0, 0 ) );


    Delivery_Id
    --| Deliver topic when identifier is that of local app
    : mC.Itf_Types.Delivery_List_Type
    := ( Count => 1,
         List  => Delivery_Id_List );


  begin

    mT.Remote_Register_Complete_Topic.Request.Data.Register
    ( Participant => Component_Main_Key,
      Detection   => mC.Itf_Types.Event_Driven,
      Role        => mC.Itf_Types.Either,
      Delivery_Id => Delivery_Id,
      Callback    => Monitor.Treat_Register_Complete'access,
      Access_Key  => Remote_Register_Complete_Topic_Access_Key,
      Status      => Data_Status );


  end;

This fixed the problem with Remote of each application transmitting the instance of the topic that was published by it to the other application of the pair where it was then delivered to the
Treat_Register_Complete procedure of the Monitor subpackage.

This might be a case that could have been fixed by pragma Volatile if it had been recognized.  That is, an example of the same thing that can happen when an object is changed by one thread and read by another without the new value being used by the code that was generated by the compiler due to its not recognizing that it could be changed.  (Or, as happens when an address is passed to a procedure that then uses it to change a value used later by the calling routine.)

The remaining gotchas were then immediately found and fixed.

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
...