Home
Categories
Dictionary
Glossary
Download
Project Details
Changes Log
What Links Here
FAQ
License

Advanced C tutorial



In the basic C tutorial, one of the modules was reimplemented in C, using a basic C module.

In this tutorial, we will use a configured C module instead.

Overview

In the basic C tutorial, we had two modules:
  • The PublishModule module increments or decrements a value cyclically. It used a basic C module
  • The EventModule module allows to click on a toggle to set if the first module should increment or decrement the value, and shows the value

XML configuration

Only the applications.xml XML file has to be modified to switch from a basic C module implementation to a configured C module.

Applications definition

We will change the applications.xml XML file, by modifying the PublishModule configuration:
      <application name="publishAppli">
         <modules>
            <cModule name="PublishModule">
               <cImplementation path="PublishModule" nativeConfig="nativeConf.xml"/>
               <interfaces>
                  <eventReceived service="event"/>
                  <cyclic service="published" frequency="200ms" attach="attach"/>
               </interfaces>
            </cModule>
         </modules>
      </application>

Develop the PublishModule in C

Create the CodeBlocks project

We will first create a new PublishModule project in CodeBlocks. See the Setting a CodeBlocks project for a C module for more information on how to do it.

Define the header

We have one service notification for the event service. We will specify a receive function in the C interface for this service notification. As this service has one boolean data, we will have one bool argument:
      #include <stdbool.h>
      
      __declspec(dllexport) void receive(bool state);
We also have one service publication for the published service. We need to specify a function to set the associated function by the framework, and a function which will be called by the framework to perform the publication (because published is a cyclic service):
      static void (*InvokerInst)(int);
      
      __declspec(dllexport) void publish();
   
      __declspec(dllexport) void setInvoker(void (*InvokerInst)(int));      
  • The setInvoker(void (*InvokerInst)(int)) allows to set the address of the function that the C code must call to invoke the published service
  • The static void (*InvokerInst)(int) is the memorization of the pointer to this function
Additionnally (but its up to the C code), we will also keep two static variables to keep the step value and the current incrementation value:
      static int count = 0;
      static int step = 1;
We have therefore the following header:
      #include <stdbool.h>
      static int count = 0;
      static int step = 1;
         
      static void (*InvokerInst)(int);

      __declspec(dllexport) void publish();
   
      __declspec(dllexport) void receive(bool state);
   
      __declspec(dllexport) void setInvoker(void (*InvokerInst)(int));

Define the source

First of all, we must store the pointer to the invoker function when the setInvoker(void (*InvokerInst)(int)) will be called:
      void setInvoker(void (*Invoker)(int)) {
         InvokerInst = Invoker;
      }     
When we receive the event service, we will trigger the receive function:
      void receive(bool state)
      {
         if (state) {
           step = -1;
         } else {
           step = 1;
         }
      }  
And now when we are cyclicallly called for the published service, we trigger the publish function:
      void publish()
      {
         count += step;
         InvokerInst(count);
      }      
The final source code is:
      #include <stdio.h>
      #include "module1.h" // this is our C header
      #include <windows.h>
      #include <stdbool.h>

      void publish()
      {
         count += step;
         InvokerInst(count);
      }

      void receive(bool state)
      {
         if (state) {
           step = -1;
         } else {
           step = 1;
         }
      }

      void setInvoker(void (*Invoker)(int)) {
         InvokerInst = Invoker;
      }

Specify the interfacing configuration

First of all we must define a Java class which will perform the interface:
      <nativeConfig libPath="org.da.testutils.clibrary.CLibrary">  
      </nativeConfig>
We will see in the next paragraph how we will specify this class. But for the moment, we need to specify the bridge from the services to* the C functions.

Specify the publish interfacing configuration

The published invoke service will be bridged to the publish function. There is only one argument, which is the counter value:
      <nativeConfig libPath="org.da.testutils.clibrary.CLibrary">
         <invokeServices>
            <invokeService name="published">
               <argument name="value" />
            </invokeService>       
         </invokeServices>
      </nativeConfig>

Specify the notification interfacing configuration

The event notified service will be bridged to the event function. There is only one argument, which is the bolean representing the state::
      <nativeConfig libPath="org.da.testutils.clibrary.CLibrary">
         <notifServices>
            <notifService name="event">
               <argument name="event" />
            </notifService>
         </notifServices>    
      </nativeConfig>

Complete interfacing configuration

      <nativeConfig libPath="org.da.testutils.clibrary.CLibrary">  
         <invokeServices>
            <invokeService name="published">
               <argument name="value" />
            </invokeService>       
         </invokeServices>
         <notifServices>
            <notifService name="event">
               <argument name="event" />
            </notifService>
         </notifServices>    
      </nativeConfig>

Specify the Java class which will perform the interface

We must develop a JNA com.sun.jna.Library interface which will as as a the bridge between the natvie code and the framework:
      public interface CLibrary extends Library {
      }      
The event service is a notification and is bridged with the receive function:
      public interface CLibrary extends Library {
         @SignatureTag(type=SignatureType.NOTIFICATION, name="event")
         public void receive(boolean state);
         }   
      }      
The published service is an invocation and is bridged with the setInvoker function:
      public interface CLibrary extends Library {
         @SignatureTag(type=SignatureType.CYCLIC_SERVICE, name="published")
         public void publish();       
      
         @SignatureTag(type=SignatureType.INVOCATION, name="published")
         public void setInvoker(Invoker callback);

         public interface Invoker extends Callback {
           void invoke(int value);
         }  
      }      
We have the following code for the interface:
      public interface CLibrary extends Library {
         @SignatureTag(type=SignatureType.NOTIFICATION, name="event")
         public void receive(boolean state);
   
         @SignatureTag(type=SignatureType.CYCLIC_SERVICE, name="published")
         public void publish();   
   
         @SignatureTag(type=SignatureType.INVOCATION, name="published")
         public void setInvoker(Invoker callback);

         public interface Invoker extends Callback {
           void invoke(int value);
         }   
      }      
Now we must generate a jar file with this interface, and add this jar file to the decployment for our module:
      <application name="publishAppli">
         <deployment>
            <lib url="CLibrary.jar" />
         </deployment>      
         <modules>
            <cModule name="PublishModule"> 
               <cImplementation path="PublishModule2" nativeConfig="nativeConfig.xml"/>
               <interfaces>
                  <eventReceived service="event"/>
                  <cyclic service="published" frequency="200ms" attach="attach"/>
               </interfaces>             
            </cModule>
         </modules>
      </application>

See also


Categories: tutorials

Copyright 2017-2020 Dassault Aviation. All Rights Reserved. Documentation and source under the LGPL v3 licence