Commit f9f1a5f1 authored by Maxime Perrotin's avatar Maxime Perrotin
parents bc7e85a0 a78007a8
......@@ -2,10 +2,11 @@ Current maintainer is
- Jerome Hugues
Contributors
- Raphael Defoin (2018)
- Antonia Francis (2018)
- Hariprasath Shanmugasundaram (2017)
The initial design team of PolyORB-HI/C was
- Julien Delange (up to 2016)
- Julien Delange (initial author, up to 2016)
- Jerome Hugues
- Laurent Pautet (up to 2009)
......@@ -221,6 +221,7 @@ AC_OUTPUT([
examples/aadlv2/file-store/Makefile
examples/aadlv2/latency/Makefile
examples/aadlv2/rma/Makefile
examples/aadlv2/rpc/Makefile
examples/aadlv2/some-types/Makefile
examples/aadlv2/some-types-stdint/Makefile
examples/aadlv2/sunseeker/Makefile
......
SUBDIRS = d3.1.3-1 ping rma sunseeker producer-consumer some-types \
some-types-stdint flight-mgmt import monitor lua cpp \
packet-store file-store latency code_coverage torture_gqueue
packet-store file-store latency code_coverage torture_gqueue \
rpc
SAMPLE_DIR = ${shell $(CYGPATH_U) '$(OCARINA_PREFIX)/examples/ocarina/polyorb-hi-c/aadlv2'}
......
#!/bin/sh
for i in "$@"
do
case $i in
--output-dir-name=*)
OUTPUT_DIR="${i#*=}" #ONLY NAME OF DIR
shift # past argument=value
;;
*)
# unknown option
;;
esac
done
if [ -z "$OUTPUT_DIR" ]; then
OUTPUT_DIR=./gcov_output
else
OUTPUT_DIR=./$OUTPUT_DIR
fi
if (! test -d $OUTPUT_DIR )
then
echo "Missing path: $OUTPUT_DIR. Creating directory..."
mkdir $OUTPUT_DIR
fi
lcov -c -i -d . -o .coverage.base
lcov -c -d . -o .coverage.run
lcov -d . -a .coverage.base -a .coverage.run -o .coverage.total
genhtml --no-branch-coverage -o $OUTPUT_DIR .coverage.total
rm -f .coverage.base .coverage.run .coverage.total
This diff is collapsed.
#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <types.h>
int16_t boolean_type_var = 0;
int32_t integer_type_var = 0;
int64_t natural_type_var = 0;
void user_emit_boolean( int16_t* boolean)
int8_t int8_type_var = 0;
int16_t int16_type_var = 0;
int32_t int32_type_var = 0;
int64_t int64_type_var = 0;
uint8_t uint8_type_var = 0;
uint16_t uint16_type_var = 0;
uint32_t uint32_type_var = 0;
uint64_t uint64_type_var = 0;
float_t float0_type_var = 0.0;
float_t float32_type_var = 0.0;
double_t float64_type_var = 0.0;
char char_type_var = 'A';
/* Macros Definition */
/* Integer */
#define EMIT_TYPE_INT(TYPE, VAR, FORMAT) \
void user_emit_##TYPE (VAR * type) \
{\
TYPE##_type_var++; \
*type = TYPE##_type_var;\
printf("Emetting integer : ");\
printf(FORMAT, *type);\
printf("\n"); \
fflush (stdout); \
}
#define RECEIVE_TYPE_INT(TYPE, VAR, FORMAT) \
void user_receive_##TYPE (VAR type)\
{\
printf("Receiving integer : ");\
printf(FORMAT, type);\
printf("\n"); \
fflush (stdout); \
}
/* Float */
#define EMIT_TYPE_FLOAT(TYPE, VAR, FORMAT) \
void user_emit_##TYPE (VAR * type) \
{\
TYPE##_type_var++; \
*type = TYPE##_type_var;\
printf("Emetting float : ");\
printf(FORMAT, *type);\
printf("\n"); \
fflush (stdout); \
}
#define RECEIVE_TYPE_FLOAT(TYPE, VAR, FORMAT) \
void user_receive_##TYPE (VAR type)\
{\
printf("Receiving float : ");\
printf(FORMAT, type);\
printf("\n"); \
fflush (stdout); \
}
/* Boolean sub case */
void user_emit_boolean(int16_t* boolean)
{
if (boolean_type_var == 1)
{
......@@ -16,21 +85,93 @@ void user_emit_boolean( int16_t* boolean)
}
*boolean = boolean_type_var;
printf ("Sending boolean : %d\n", *boolean);
fflush (stdout);
}
void user_receive_boolean (int16_t boolean)
{
printf ("Receiving boolean : %d\n", boolean);
fflush (stdout);
}
void user_emit_integer( int32_t* integer)
/* Char sub case */
void user_emit_char (char* character)
{
integer_type_var++;
*integer = integer_type_var;
printf ("Emetting integer : %d\n", *integer);
char_type_var = 'A' + ((char_type_var - 'A' +1) %26) ;
*character = (char)char_type_var;
printf ("Emetting char : %c\n", *character);
fflush (stdout);
}
void user_receive_integer (int32_t integer)
void user_receive_char (char character)
{
printf ("Receiving integer : %d\n", integer);
printf ("Receiving char : %c\n", character);
fflush (stdout);
}
/* Array sub case */
void user_emit_array (software__array_type* data)
{
int i;
for (i = 0; i < 16; i++)
{(*data)[i]=i;}
printf ("Emetting array\n");
fflush (stdout);
}
void user_receive_array (software__array_type data)
{
int i;
printf("Receive array: ");
for (i = 0; i < 16; i++)
{assert (data[i] == i);}
printf ("OK \n");
fflush(stdout);
}
/* Appel des fonctions */
EMIT_TYPE_INT(integer, int32_t, "%d")
RECEIVE_TYPE_INT(integer, int32_t, "%d")
EMIT_TYPE_INT(natural, int64_t, "%lld")
RECEIVE_TYPE_INT(natural, int64_t, "%lld")
EMIT_TYPE_INT(int8,int8_t, "%hhd")
RECEIVE_TYPE_INT(int8,int8_t, "%hhd")
EMIT_TYPE_INT(int16,int16_t, "%d")
RECEIVE_TYPE_INT(int16,int16_t, "%d")
EMIT_TYPE_INT(int32,int32_t, "%d")
RECEIVE_TYPE_INT(int32,int32_t, "%d")
EMIT_TYPE_INT(int64,int64_t, "%ld")
RECEIVE_TYPE_INT(int64,int64_t, "%ld")
EMIT_TYPE_INT(uint8,uint8_t, "%hhu")
RECEIVE_TYPE_INT(uint8,uint8_t, "%hhu")
EMIT_TYPE_INT(uint16,uint16_t, "%u")
RECEIVE_TYPE_INT(uint16,uint16_t, "%u")
EMIT_TYPE_INT(uint32,uint32_t,"%u")
RECEIVE_TYPE_INT(uint32,uint32_t, "%u")
EMIT_TYPE_INT(uint64,uint64_t, "%lu")
RECEIVE_TYPE_INT(uint64,uint64_t, "%lu")
EMIT_TYPE_FLOAT(float0,float_t, "%lf")
RECEIVE_TYPE_FLOAT(float0,float_t, "%lf")
EMIT_TYPE_FLOAT(float32,float_t, "%lf")
RECEIVE_TYPE_FLOAT(float32,float_t, "%lf")
EMIT_TYPE_FLOAT(float64,double_t, "%llf")
RECEIVE_TYPE_FLOAT(float64,double_t,"%llf")
C_FILES = $(srcdir)/rpc.c
AADL_FILES = $(srcdir)/rpc.aadl
SCENARIO_FILES = $(srcdir)/scenario.aadl
include $(srcdir)/../../Makefile.common
EXTRA_DIST = $(AADL_FILES) $(SCENARIO_FILES) $(C_FILES)
CLEANDIRS = rpc_impl
package RPC
-- This example illustrates how to emulate RPC synchronous (or
-- rendez-vous) interactions using a tuple of parameter/return value
-- ports, and the AADL runtime services.
public
with Data_Model;
with Deployment;
---------------
-- Processes --
---------------
-- RPC_Process host two threads interacting in a synchronou way: a
-- client and a server
process RPC_Process
end RPC_Process;
process implementation RPC_Process.Impl
subcomponents
Client_T : thread Client_Thread.Impl;
Server_T : thread Server_Thread.Impl;
connections
C1 : port Client_T.Out_Parameter -> Server_T.In_Parameter;
C2 : port Server_T.Return_Value -> Client_T.Return_Value;
end RPC_Process.Impl;
-------------
-- Threads --
-------------
thread Client_Thread
features
Out_Parameter : out event data port Alpha_Type;
Return_Value : in event data port Alpha_Type;
end Client_Thread;
thread implementation Client_Thread.Impl
-- In the case of the client-side of the RPC: the corresponding
-- AADL subprogram is *NOT* connected to AADL thread ports. The
-- Client_Side_Function interacts directly with the port
-- variables to emulate a RPC synchronous call:
--
-- 1/ we send the parameter through the "out_parameter" port
-- 2/ we block and wait for return parameters through the return_value
properties
Dispatch_Protocol => Periodic;
Period => 1 sec;
Priority => 110;
Compute_Entrypoint => classifier (Client_Side_Function);
end Client_Thread.Impl;
thread Server_Thread
features
In_Parameter : in event data port Alpha_Type;
Return_Value : out event data port Alpha_Type;
end Server_Thread;
thread implementation Server_Thread.Impl
-- In the case of the server-side RPC: the server function is
-- connected to the input parameter and return value ports, we
-- take advantage of port-to-parameter conenctions to hook the
-- server code directly. It is sporadic to reflect it server
-- nature: ut reacts to incoming events representing the arrival
-- of in parameters and will answer back through the return_value
-- port.
calls
Mycalls: {
S_Spg : subprogram Server_Side_Function;
};
connections
parameter S_Spg.Return_Value -> Return_Value;
parameter In_Parameter -> S_Spg.In_Parameter;
properties
Dispatch_Protocol => Sporadic;
Period => 10 ms;
end Server_Thread.Impl;
----------
-- Data --
----------
data Alpha_Type
properties
Data_Model::Data_Representation => integer;
end Alpha_Type;
-----------------
-- Subprograms --
-----------------
subprogram Server_Side_Function
features
In_Parameter : in parameter Alpha_Type;
Return_Value : out parameter Alpha_Type;
properties
Source_Language => (C);
Source_Name => "rpc_server";
Source_Text => ("rpc.c");
end Server_Side_Function;
subprogram Client_Side_Function
features
Out_Parameter : out parameter Alpha_Type;
Return_Value : in parameter Alpha_Type;
properties
Source_Language => (C);
Source_Name => "rpc_client";
Source_Text => ("rpc.c");
end Client_Side_Function;
---------------
-- Processor --
---------------
processor the_processor
properties
Deployment::Execution_Platform => Native;
end the_processor;
processor implementation the_processor.i
end the_processor.i;
------------
-- System --
------------
system RPC
end RPC;
system implementation RPC.Impl
subcomponents
RPC : process RPC_Process.Impl;
CPU : processor the_processor.i;
properties
Actual_Processor_Binding => (reference (CPU)) applies to RPC;
end RPC.Impl;
end RPC;
#include <aadl.h>
#include <stdio.h>
/* Files generated from AADL model */
#include <request.h>
#include <deployment.h>
#include "types.h"
#include <po_hi_transport.h>
#include <po_hi_gqueue.h>
/******************************************************************************/
/* In the case of the client-side of the RPC: the corresponding AADL
* subprogram is *NOT* connected to AADL thread ports. We interact
* directly with the port variables to emulate a RPC synchronous call:
* 1/ we send the parameter through the "out_parameter" port
* 2/ we block and wait for return parameters through the return_value
*/
void rpc_client (__po_hi_task_id self) {
static int i = 0;
__po_hi_request_t req;
__po_hi_local_port_t return_value_port;
printf ("[START of RPC]\n");
req.port = REQUEST_PORT (client_t, out_parameter);
req.PORT_VARIABLE (client_t,out_parameter) = i;
__po_hi_gqueue_store_out
(self,
LOCAL_PORT (client_t,out_parameter),
&req);
__po_hi_send_output (self,REQUEST_PORT(client_t, out_parameter));
printf ("Client thread: sending parameter %d\n", i);
__po_hi_gqueue_wait_for_incoming_event(self, &return_value_port);
__po_hi_gqueue_get_value(self,return_value_port,&req);
__po_hi_gqueue_next_value(self,return_value_port);
printf ("Client received: %d\n",
req.PORT_VARIABLE(client_t,return_value));
i++;
printf ("[END of RPC]\n\n");
}
/******************************************************************************/
/* In the case of the server-side RPC: the server function is
* connected to the input parameter and return value ports, we take
* advantage of port-to-parameter conenctions to hook the server code
* directly
*/
void rpc_server
(rpc__alpha_type in_parameter,
rpc__alpha_type* return_value)
{
printf ("Server thread: received %d\n", in_parameter);
*return_value = in_parameter + 1;
printf ("Server thread: sending return value %d\n", *return_value);
}
package Scenario
public
with Ocarina_Config;
with Ocarina_Library;
system producer_consumer extends Ocarina_Library::Default_PolyORB_HI_C_Config
properties
Ocarina_Config::Timeout_Property => 10500ms;
Ocarina_Config::AADL_Files +=>
("rpc.aadl");
Ocarina_Config::Root_System_Name => "rpc.impl";
end producer_consumer;
system implementation producer_consumer.Impl
end producer_consumer.Impl;
end scenario;
\ No newline at end of file
......@@ -88,8 +88,29 @@ sent, but the previous one (inferior by 1). assert (reception !=
sent_level ); assert (reception == sent_level - 1); The other port
constitutes a control assay.
Test Sporadic 6 :
These tests are used to verify the behavior when working with IN DATA PORTS
and not IN EVENT DATA PORTS. It allows us to get a coverage of 100% of the code
with this test file.
Initially we verify that the reception has been done well.
First we use a get_value function, and then a next_value before verifying that
a get_count on a IN DATA PORT always gives back the value 1 and an used_size
always giving back the value 0.
Thay behavior awaited is illustrated by Beware Warnings.
We try a get_value on an empty port and finally we dequeue the event
sent from Period Port P2 to Sporad Port P1 to trigger the sporadic task.
## Periodic Test details
Each time messages are sent by the periodic task and received by itself.
The Per Port P3 is linked to the Per Port P4.
The Per Port P5 is linked to the Per Port P6.
Test Periodic 1 :
This time, two messages are sent on the port P3 towards port P4 of the
periodic task : the task are sending messages to itself.
......@@ -112,3 +133,18 @@ incrementation is of 1 at each awakening, it is easy to recover the
previous value sent thanks to the assertion : reception == sent_lvl -
number + j + 1. The value is then dequeued to get to the following
value.
Test Periodic 2 :
This time two messages are as well sent to the periodic task to itself.
The goal is to verify whether, if the queue is full, only a message is received
and it is the first one.The transport file must send an error message and prevent
the sending of the file.
The goal is then to verify whether the store_in function is also blocked
when the queue of the destined port isfull.
In both cases we verify that the message first sent is not erased by the other ones,
respectively supposedly not transmitted and not stored_in.
If messages are printed, then the test is passed.
In another hand, the goal is to verify that a get_value on an output port
gives right back an error message.
......@@ -15,6 +15,9 @@ public
P2 : out event data port int;
P3 : out event data port int;
P4 : in event data port int { Queue_Size => 42;};
P5 : out event data port int;
P6 : in event data port int {Queue_Size => 1;};
P7 : out data port int; -- XXX
properties
Dispatch_Protocol => Periodic;
Period => 1000 ms;
......@@ -29,9 +32,8 @@ public
thread Spo1
features
P1 : in event data port int { Queue_Size => 42;};
P2 : in event data port int { Queue_Size => 42;};
P3 : out event data port Int;
P4 : in event data port int { Queue_Size => 42;};
P2 : in event data port int { Queue_Size => 42;};
P3 : in data port int;
properties
Dispatch_Protocol => Sporadic; -- Concurrency configuration
Period => 100 ms;
......@@ -54,8 +56,9 @@ public
connections
C1 : port Per_thread.P2 -> Spo_thread.P1;
C2 : port Per_thread.P1 -> Spo_thread.P2;
C3 : port Spo_thread.P3 -> Spo_thread.P4;
C4 : port Per_thread.P3 -> Per_thread.P4;
C3 : port Per_thread.P3 -> Per_thread.P4;
C4 : port Per_thread.P5 -> Per_thread.P6;
C5 : port Per_thread.P7 -> Spo_thread.P3;
end Torture_Software.impl;
......
This diff is collapsed.
USER_CFLAGS=-g
USER_CFLAGS=-D__PO_HI_USE_GPROF
COVERAGE=gcov
......@@ -12,7 +12,7 @@ EXTRA_DIST = $(srcdir)/po_hi_common.h $(srcdir)/po_hi_debug.h \
$(srcdir)/po_hi_task.h $(srcdir)/po_hi_time.h \
$(srcdir)/po_hi_types.h $(srcdir)/po_hi_main.h \
$(srcdir)/po_hi_simulink.h $(srcdir)/po_hi_transport.h \
$(srcdir)/po_hi_semaphore.h
$(srcdir)/po_hi_semaphore.h $(srcdir)/aadl.h
CLEANFILES = *~
......
/*
* This is a part of PolyORB-HI-C distribution, a minimal
* middleware written for generated code from AADL models.
* You should use it with the Ocarina toolsuite.
*
* For more informations, please visit http://taste.tuxfamily.org/wiki
*
* Copyright (C) 2018 ESA & ISAE.
*/
/**
* This header file defines data types and functions to support the
* AADL Code Generation Annex (Annex C) published in document
* AS5506/1A.
*
*/
#include <deployment.h>
/**
* Definition of AADL thread context (AS5506/1A C.6.3)
*
* Note: in PolyORB-HI/C, all port variables are part of the internal
* structure defined in po_hi_gqueue.h. The thread context is
* therefore limited to the identifier of a task.
*/
typedef __po_hi_task_id __aadl_context;
/**
* Helper macros to access AADL entities
*
* A typical use case is
*
* 1) Definition of AADL request type
* __po_hi_request_t request;
*
* 2) Definition of the output port to use
* request.port = REQUEST_PORT (a_thread, a_port);
*
* 3) Assignment to the corresponding port variable
* request.PORT_VARIABLE (a_thread, a_port) = a_value;
*
* 4) We send the request through the thread *local* port, built from
* the instance name and the port name using the LOCAL_PORT
* macro. PolyORB-HI/C middleware will later propagate the request to
* its destination
*
* __po_hi_gqueue_store_out
* (self,
* LOCAL_PORT (waterlevelmonitoring_thread, wateralarm),
* &request);
*
*/
#define LOCAL_PORT(THREAD_INSTANCE_NAME, PORT_NAME) THREAD_INSTANCE_NAME ## _local_ ## PORT_NAME
/**
* REQUEST_PORT macro builds a handle to the output port used when
* building a request
*/
#define REQUEST_PORT(THREAD_INSTANCE_NAME, PORT_NAME) THREAD_INSTANCE_NAME ## _global_ ## PORT_NAME
/**
* PORT_VARIABLE macro build a handle to a port variable
*/
#define PORT_VARIABLE(THREAD_INSTANCE_NAME, PORT_NAME) vars.REQUEST_PORT(THREAD_INSTANCE_NAME,PORT_NAME).REQUEST_PORT(THREAD_INSTANCE_NAME,PORT_NAME)
/**
* Put_Value (AS5506C): A Put_Value runtime service allows the source
* text of a thread to supply a data value to a port variable. This
* data value will be transmitted at the next Send_Output call in the
* source text or by the runtime system at completion time or
* deadline.
*
* subprogram Put_Value features
* Portvariable: requires data access; -- reference to port variable
* DataValue: in parameter; -- value to be stored
* DataSize: in parameter; -- size in bytes (optional)
* end Put_Value;
*
*/
......@@ -336,8 +336,7 @@ endif
ifeq ($(TARGET), $(filter $(TARGET), native bench linux32 linux64 linux32_dll linux64_dll))
EXE=$(BINARY)$(EXEEXT)
$(BINARY):
$(MAKE) generate-asn1-deployment target-objects compile-c-files compile-cpp-files compile-ada-files compile-po-hi $(USER_OBJS) $(GENERATED_OBJS) $(TARGET_OBJECTS)
$(BINARY): generate-asn1-deployment target-objects compile-c-files compile-cpp-files compile-ada-files compile-po-hi $(USER_OBJS) $(GENERATED_OBJS) $(TARGET_OBJECTS)
$(LD) -o $(EXE) $(EXTERNAL_OBJECTS) $(PO_HI_OBJS) $(PO_HI_CPPOBJS) $(GENERATED_OBJS) $(USER_OBJS) $(LDFLAGS)
endif
......
......@@ -268,6 +268,7 @@ void __po_hi_gqueue_init (__po_hi_task_id id,
assert(__po_hi_gqueues_used_size[id][i] == 0);
assert(__po_hi_gqueues_most_recent_values[id][i].port == __PO_HI_GQUEUE_INVALID_PORT);
if (i > 0){
/* Usually HAS TO be right */
//assert(__po_hi_gqueues_first[id][i] >= 0);
}
}
......@@ -317,7 +318,6 @@ __po_hi_port_id_t __po_hi_gqueue_store_in (__po_hi_task_id id,
__DEBUGMSG ("__po_hi_gqueue_store_in : NULL POINTER\n");
}
#endif
/* Locking only a mutex */
__PO_HI_DEBUG_DEBUG ("\nWaiting on Store_in on task %d, port = %d, size of port = %d\n", id, port,__po_hi_gqueue_get_port_size(id, port));
int result = __po_hi_sem_mutex_wait_gqueue(__po_hi_gqueues_semaphores,id);
......@@ -327,6 +327,7 @@ __po_hi_port_id_t __po_hi_gqueue_store_in (__po_hi_task_id id,
if (__po_hi_gqueue_get_port_size(id,port) == __PO_HI_GQUEUE_FIFO_INDATA)
{
memcpy(ptr,request,sizeof(*request));
__PO_HI_DEBUG_CRITICAL ("[GQUEUE] BEWARE, for a FIFO_INDATA port, the used_size is always at 0 (not augmented in a store_in) task-id=%d, port=%d\n", id, port);
}
else
{
......@@ -386,7 +387,6 @@ __po_hi_port_id_t __po_hi_gqueue_store_in (__po_hi_task_id id,
int rel = __po_hi_sem_release_gqueue(__po_hi_gqueues_semaphores,id);
__DEBUGMSG("GQUEUE_SEM_RELEASE %d %d\n", id, rel);
assert(rel == __PO_HI_SUCCESS);
__DEBUGMSG ("[GQUEUE] store_in completed\n");
#ifdef __PO_HI_GQUEUE_ASSERTIONS
......@@ -460,6 +460,7 @@ int __po_hi_gqueue_get_count( __po_hi_task_id id, __po_hi_local_port_t port)
{
if (__po_hi_gqueue_get_port_size(id,port) == __PO_HI_GQUEUE_FIFO_INDATA)
{
__PO_HI_DEBUG_CRITICAL ("[GQUEUE] BEWARE a FIFO_INDATA port will always have a get_count of 1, even if empty, task-id=%d, port=%d\n", id, port);
return 1; /* data port are always of size 1 */
}
else
......@@ -488,15 +489,21 @@ int __po_hi_gqueue_get_value (__po_hi_task_id id,
* If the port is an OUTPUT, with no value queued, the function returns
* nothing.
*/
if (__po_hi_gqueue_get_port_size(id,port) == 0)
if (__po_hi_gqueue_get_port_size(id,port) == -2)
{
__PO_HI_DEBUG_CRITICAL ("[GQUEUE] OUTPUT PORT, REQUEST NOT SET UP, task-id=%d, port=%d\n", id, port);
__DEBUGMSG("THE PORT IS AN OUTPUT, REQUEST NOT SET UP");
return 0;
/* Releasing only the mutex of the semaphore*/
int rel = __po_hi_sem_mutex_release_gqueue(__po_hi_gqueues_semaphores,id);