Services

In order to promote uniformity in the management of threads, and in particular of the thread initialisation and destruction processes, the framework offers a thread service abstraction (see EmbeddedServiceI).

The following use-cases are covered: single-thread, multi-thread (each concurring for the same resource) and client oriented connection (e.g. web server).

The callback function (called by the service) shall have the following prototype: (MARTe::ErrorManagement::ErrorType (*)(MARTe::EmbeddedServiceI::ExecutionInfo &)). The name of the callback function is registered by implementing the EmbeddedServiceMethodBinderT interface.

All service implementations will continuously call the callback function with a given state (represented by the input ExecutionInfo). The service will act accordingly to the returned value (see below).

Note

The callback function shall avoid blocking the execution and return as soon as possible.

Any of the EmbeddedServices offers a Start and a Stop method. The latter guarantees that the thread is killed if it not gracefully terminated by the application with-in a given timeout period.

All the thread parameters (affinity, stack, number of threads, …) can be changed using the specific service API or using the standard Initialise method.

SingleThreadService

The SingleThreadService commands an EmbeddedThread which in turn continuously call the registered callback function with one of the stages set below.

../../_images/SingleThreadService-1.png

Depending on the callback return value, the ExecutionInfo stage of each callback call is set as follows:

Stage

Condition(s)

StartupStage

After SingleThreadService::Start().

If the callback returns an ErrorType which is not NoError and SingleThreadService::Stop() was not called.

MainStage

Until SingleThreadService::Stop() is called or if the callback returns an ErrorType which is not NoError.

TerminationStage

If the callback returns an ErrorType which is ErrorManagement::Completed.

BadTerminationStage

If the callback returns an ErrorType which is not ErrorManagement::Completed or if SingleThreadService::Stop() was called.

AsyncTerminationStage

If the thread was killed after trying to gracefully terminate with a SingleThreadService::Stop().

The first time the SingleThreadService::Stop() is called, the EmbeddedThread will wait for the callback function to return and will call it one last time with the ExecutionInfo stage set to BadTerminationStage.

If, in the meanwhile, the SingleThreadService::Stop() is called a second time, the thread will be killed (see Kill in the Threads API) and the callback will be (asynchronously) called with the ExecutionInfo stage set to AsyncTerminationStage.

Warning

The service can only be killed if a finite timeout was configured, otherwise it will wait forever to be gracefully stopped.

MultiThreadService

The MultiThreadService offers an equivalent function to the EmbeddedServiceI with one or more threads. The threads will concurrently call the callback function.

../../_images/MultiThreadService-1.png

MultiClientService

The MultiClientService is a connection oriented implementation of the service described above. In particular the GetStageSpecific of the ExecutionInfo is used to trigger connection oriented events:

StageSpecific

Condition(s)

WaitRequestStageSpecific

Wait for a connection request.

ServiceRequestStageSpecific

Serve a specific request.

../../_images/MultiClientService-1.png

The number of threads is allowed to be increased/decreased by the service between the values defined by GetMinimumNumberOfPoolThreads () and GetMaximumNumberOfPoolThreads ().

Note

The callback should not block and should return ErrorManagement::Timeout while awaiting for a connection to be established. After a connection is established (ServiceRequestStageSpecific) the callback shall return ErrorManagement::Completed when the service has been completed.

Examples

SingleThreadService

The following is an example which highlights all the possible ExecutionInfo callback stages.

Example of a SingleThreadService
  1/**
  2 * @file SingleThreadServiceExample1.cpp
  3 * @brief Source file for class SingleThreadServiceExample1
  4 * @date 24/04/2018
  5 * @author Andre Neto
  6 *
  7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
  8 * the Development of Fusion Energy ('Fusion for Energy').
  9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 11 * You may not use this work except in compliance with the Licence.
 12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 13 *
 14 * @warning Unless required by applicable law or agreed to in writing, 
 15 * software distributed under the Licence is distributed on an "AS IS"
 16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 17 * or implied. See the Licence permissions and limitations under the Licence.
 18
 19 * @details This source file contains the definition of all the methods for
 20 * the class SingleThreadServiceExample1 (public, protected, and private). Be aware that some
 21 * methods, such as those inline could be defined on the header file, instead.
 22 */
 23#define DLL_API
 24/*---------------------------------------------------------------------------*/
 25/*                         Standard header includes                          */
 26/*---------------------------------------------------------------------------*/
 27
 28/*---------------------------------------------------------------------------*/
 29/*                         Project header includes                           */
 30/*---------------------------------------------------------------------------*/
 31#include "AdvancedErrorManagement.h"
 32#include "BasicTCPSocket.h"
 33#include "ConfigurationDatabase.h"
 34#include "ErrorLoggerExample.h"
 35#include "EmbeddedServiceMethodBinderT.h"
 36#include "ObjectRegistryDatabase.h"
 37#include "StandardParser.h"
 38#include "SingleThreadService.h"
 39
 40/*---------------------------------------------------------------------------*/
 41/*                           Static definitions                              */
 42/*---------------------------------------------------------------------------*/
 43
 44namespace MARTe2Tutorial {
 45/**
 46 * @brief a class that contains a single thread service with an embedded binder.
 47 */
 48class SingleThreadServiceExample1: public MARTe::Object, public MARTe::EmbeddedServiceMethodBinderT<SingleThreadServiceExample1> {
 49
 50public:
 51    CLASS_REGISTER_DECLARATION()SingleThreadServiceExample1() :
 52    MARTe::Object(), MARTe::EmbeddedServiceMethodBinderT<SingleThreadServiceExample1>(*this, &SingleThreadServiceExample1::ThreadCallback), service(
 53            *this) {
 54        counter = 0u;
 55    }
 56
 57    virtual ~SingleThreadServiceExample1() {
 58        using namespace MARTe;
 59        if (GetName() != NULL) {
 60            REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
 61                    "pointing at %s [%s]. The Object will "
 62                    "be safely deleted.",
 63                    GetName(), GetClassProperties()->GetName());
 64        }
 65    }
 66
 67    virtual bool Initialise(MARTe::StructuredDataI &data) {
 68        bool ok = MARTe::Object::Initialise(data);
 69        if (ok) {
 70            ok = service.Initialise(data);
 71        }
 72        return ok;
 73    }
 74
 75    MARTe::ErrorManagement::ErrorType ThreadCallback(MARTe::ExecutionInfo &info) {
 76        using namespace MARTe;
 77        ErrorManagement::ErrorType err;
 78        if (info.GetStage() == ExecutionInfo::StartupStage) {
 79            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::StartupStage");
 80        }
 81        else if (info.GetStage() == ExecutionInfo::MainStage) {
 82            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::MainStage");
 83            if (counter == 0u) {
 84                err = ErrorManagement::Completed;
 85            }
 86            else {
 87                err = ErrorManagement::FatalError;
 88            }
 89        }
 90        else if (info.GetStage() == ExecutionInfo::TerminationStage) {
 91            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::TerminationStage");
 92            err = ErrorManagement::NoError;
 93            counter++;
 94        }
 95        else if (info.GetStage() == ExecutionInfo::BadTerminationStage) {
 96            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::BadTerminationStage");
 97            counter++;
 98            //Simulate error to force killing
 99            while (true) {
100                Sleep::Sec(0.2);
101            }
102        }
103        else if (info.GetStage() == ExecutionInfo::AsyncTerminationStage) {
104            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::AsyncTerminationStage");
105            err = ErrorManagement::NoError;
106        }
107        Sleep::Sec(0.2);
108        return err;
109    }
110
111    MARTe::SingleThreadService service;
112    MARTe::uint32 counter;
113};
114
115CLASS_REGISTER(SingleThreadServiceExample1, "")
116}
117
118/*---------------------------------------------------------------------------*/
119/*                           Method definitions                              */
120/*---------------------------------------------------------------------------*/
121
122int main(int argc, char **argv) {
123    using namespace MARTe;
124    using namespace MARTe2Tutorial;
125    SetErrorProcessFunction(&ErrorProcessExampleFunction);
126
127    StreamString configurationCfg = ""
128            "+SingleThreadServiceExample1 = {\n"
129            "    Class = SingleThreadServiceExample1\n"
130            "    Timeout = 100\n" //100 ms
131            "    CPUMask = 0x1\n"
132            "}";
133
134    REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
135    ConfigurationDatabase cdb;
136    StreamString err;
137    //Force the string to be seeked to the beginning.
138    configurationCfg.Seek(0LLU);
139    StandardParser parser(configurationCfg, cdb, &err);
140    bool ok = parser.Parse();
141    ObjectRegistryDatabase *ord = ObjectRegistryDatabase::Instance();
142    if (ok) {
143        //After parsing the tree is pointing at the last leaf
144        cdb.MoveToRoot();
145        ok = ord->Initialise(cdb);
146    }
147    else {
148        StreamString errPrint;
149        errPrint.Printf("Failed to parse %s", err.Buffer());
150        REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
151    }
152
153    ReferenceT<SingleThreadServiceExample1> singleThreadService;
154    if (ok) {
155        singleThreadService = ord->Find("SingleThreadServiceExample1");
156        ok = singleThreadService.IsValid();
157    }
158    if (ok) {
159        singleThreadService->service.Start();
160        while (singleThreadService->counter != 2) {
161            Sleep::Sec(0.2);
162        }
163        singleThreadService->service.Stop();
164        Sleep::Sec(0.2);
165        //Kill the service
166        singleThreadService->service.Stop();
167    }
168    //Purge all the Objects!
169    ObjectRegistryDatabase::Instance()->Purge();
170    return 0;
171}

MultiThreadService

This is an example similar to the above but with a MultiThreadService.

Example of a MultiThreadService
  1/**
  2 * @file MultiThreadServiceExample1.cpp
  3 * @brief Source file for class MultiThreadServiceExample1
  4 * @date 24/04/2018
  5 * @author Andre Neto
  6 *
  7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
  8 * the Development of Fusion Energy ('Fusion for Energy').
  9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 11 * You may not use this work except in compliance with the Licence.
 12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 13 *
 14 * @warning Unless required by applicable law or agreed to in writing, 
 15 * software distributed under the Licence is distributed on an "AS IS"
 16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 17 * or implied. See the Licence permissions and limitations under the Licence.
 18
 19 * @details This source file contains the definition of all the methods for
 20 * the class MultiThreadServiceExample1 (public, protected, and private). Be aware that some
 21 * methods, such as those inline could be defined on the header file, instead.
 22 */
 23#define DLL_API
 24/*---------------------------------------------------------------------------*/
 25/*                         Standard header includes                          */
 26/*---------------------------------------------------------------------------*/
 27
 28/*---------------------------------------------------------------------------*/
 29/*                         Project header includes                           */
 30/*---------------------------------------------------------------------------*/
 31#include "AdvancedErrorManagement.h"
 32#include "BasicTCPSocket.h"
 33#include "ConfigurationDatabase.h"
 34#include "ErrorLoggerExample.h"
 35#include "EmbeddedServiceMethodBinderT.h"
 36#include "ObjectRegistryDatabase.h"
 37#include "StandardParser.h"
 38#include "MultiThreadService.h"
 39
 40/*---------------------------------------------------------------------------*/
 41/*                           Static definitions                              */
 42/*---------------------------------------------------------------------------*/
 43
 44namespace MARTe2Tutorial {
 45/**
 46 * @brief a class that contains a single thread service with an embedded binder.
 47 */
 48class MultiThreadServiceExample1: public MARTe::Object, public MARTe::EmbeddedServiceMethodBinderT<MultiThreadServiceExample1> {
 49
 50public:
 51    CLASS_REGISTER_DECLARATION()
 52    MultiThreadServiceExample1() :
 53    MARTe::Object(), MARTe::EmbeddedServiceMethodBinderT<MultiThreadServiceExample1>(*this, &MultiThreadServiceExample1::ThreadCallback), service(
 54            *this) {
 55        counter = NULL;
 56    }
 57
 58    virtual ~MultiThreadServiceExample1() {
 59        using namespace MARTe;
 60        if (GetName() != NULL) {
 61            REPORT_ERROR_STATIC(ErrorManagement::Information, "No more references "
 62                    "pointing at %s [%s]. The Object will "
 63                    "be safely deleted.",
 64                    GetName(), GetClassProperties()->GetName());
 65        }
 66        delete counter;
 67    }
 68
 69    virtual bool Initialise(MARTe::StructuredDataI &data) {
 70        bool ok = MARTe::Object::Initialise(data);
 71        if (ok) {
 72            ok = service.Initialise(data);
 73        }
 74        if (ok) {
 75            counter = new MARTe::uint32[service.GetNumberOfPoolThreads()];
 76            MARTe::uint32 n;
 77            for (n=0u; n<service.GetNumberOfPoolThreads(); n++) {
 78                counter[n] = 0u;
 79            }
 80        }
 81        return ok;
 82    }
 83
 84    MARTe::ErrorManagement::ErrorType ThreadCallback(MARTe::ExecutionInfo &info) {
 85        using namespace MARTe;
 86        ErrorManagement::ErrorType err;
 87        if (info.GetStage() == ExecutionInfo::StartupStage) {
 88            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::StartupStage");
 89        }
 90        else if (info.GetStage() == ExecutionInfo::MainStage) {
 91            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::MainStage");
 92            if (counter[info.GetThreadNumber()] == 0u) {
 93                err = ErrorManagement::Completed;
 94            }
 95            else {
 96                err = ErrorManagement::FatalError;
 97            }
 98        }
 99        else if (info.GetStage() == ExecutionInfo::TerminationStage) {
100            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::TerminationStage");
101            err = ErrorManagement::NoError;
102            counter[info.GetThreadNumber()]++;
103        }
104        else if (info.GetStage() == ExecutionInfo::BadTerminationStage) {
105            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::BadTerminationStage");
106            counter[info.GetThreadNumber()]++;
107            //Simulate error to force killing
108            while (true) {
109                Sleep::Sec(0.2);
110            }
111        }
112        else if (info.GetStage() == ExecutionInfo::AsyncTerminationStage) {
113            REPORT_ERROR(ErrorManagement::Information, "Callback called with ExecutionInfo::AsyncTerminationStage");
114            err = ErrorManagement::NoError;
115        }
116        Sleep::Sec(0.2);
117        return err;
118    }
119
120    MARTe::MultiThreadService service;
121    MARTe::uint32 *counter;
122};
123
124CLASS_REGISTER(MultiThreadServiceExample1, "")
125}
126
127/*---------------------------------------------------------------------------*/
128/*                           Method definitions                              */
129/*---------------------------------------------------------------------------*/
130
131int main(int argc, char **argv) {
132    using namespace MARTe;
133    using namespace MARTe2Tutorial;
134    SetErrorProcessFunction(&ErrorProcessExampleFunction);
135
136    StreamString configurationCfg = ""
137            "+MultiThreadServiceExample1 = {\n"
138            "    Class = MultiThreadServiceExample1\n"
139            "    NumberOfPoolThreads = 3\n"
140            "    Timeout = 100\n" //100 ms
141            "    CPUMask = 0x1\n"
142            "}";
143
144    REPORT_ERROR_STATIC(ErrorManagement::Information, "Loading CFG:\n%s", configurationCfg.Buffer());
145    ConfigurationDatabase cdb;
146    StreamString err;
147    //Force the string to be seeked to the beginning.
148    configurationCfg.Seek(0LLU);
149    StandardParser parser(configurationCfg, cdb, &err);
150    bool ok = parser.Parse();
151    ObjectRegistryDatabase *ord = ObjectRegistryDatabase::Instance();
152    if (ok) {
153        //After parsing the tree is pointing at the last leaf
154        cdb.MoveToRoot();
155        ok = ord->Initialise(cdb);
156    }
157    else {
158        StreamString errPrint;
159        errPrint.Printf("Failed to parse %s", err.Buffer());
160        REPORT_ERROR_STATIC(ErrorManagement::ParametersError, errPrint.Buffer());
161    }
162
163    ReferenceT<MultiThreadServiceExample1> multiThreadService;
164    if (ok) {
165        multiThreadService = ord->Find("MultiThreadServiceExample1");
166        ok = multiThreadService.IsValid();
167    }
168    if (ok) {
169        multiThreadService->service.Start();
170        uint32 n;
171        for (n=0u; n<multiThreadService->service.GetNumberOfPoolThreads(); n++) {
172            while (multiThreadService->counter[n] != 2) {
173                Sleep::Sec(0.2);
174            }
175        }
176        multiThreadService->service.Stop();
177        Sleep::Sec(0.2);
178        //Kill the service
179        multiThreadService->service.Stop();
180    }
181    //Purge all the Objects!
182    ObjectRegistryDatabase::Instance()->Purge();
183    return 0;
184}

MultiClientService

The custom component TCPSocketMessageProxyExample forwards TCP messages into MARTe messages.

Example of a MultiClientService
  1/**
  2 * @file TCPSocketMessageProxyExample.cpp
  3 * @brief Source file for class TCPSocketMessageProxyExample
  4 * @date 13/04/2018
  5 * @author Andre Neto
  6 *
  7 * @copyright Copyright 2015 F4E | European Joint Undertaking for ITER and
  8 * the Development of Fusion Energy ('Fusion for Energy').
  9 * Licensed under the EUPL, Version 1.1 or - as soon they will be approved
 10 * by the European Commission - subsequent versions of the EUPL (the "Licence")
 11 * You may not use this work except in compliance with the Licence.
 12 * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
 13 *
 14 * @warning Unless required by applicable law or agreed to in writing, 
 15 * software distributed under the Licence is distributed on an "AS IS"
 16 * basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 17 * or implied. See the Licence permissions and limitations under the Licence.
 18
 19 * @details This source file contains the definition of all the methods for
 20 * the class TCPSocketMessageProxyExample (public, protected, and private). Be aware that some 
 21 * methods, such as those inline could be defined on the header file, instead.
 22 */
 23#define DLL_API
 24/*---------------------------------------------------------------------------*/
 25/*                         Standard header includes                          */
 26/*---------------------------------------------------------------------------*/
 27
 28/*---------------------------------------------------------------------------*/
 29/*                         Project header includes                           */
 30/*---------------------------------------------------------------------------*/
 31#include "AdvancedErrorManagement.h"
 32#include "ConfigurationDatabase.h"
 33#include "Message.h"
 34#include "MessageI.h"
 35#include "StandardParser.h"
 36#include "TCPSocketMessageProxyExample.h"
 37
 38/*---------------------------------------------------------------------------*/
 39/*                           Static definitions                              */
 40/*---------------------------------------------------------------------------*/
 41
 42/*---------------------------------------------------------------------------*/
 43/*                           Method definitions                              */
 44/*---------------------------------------------------------------------------*/
 45
 46namespace MARTe2Tutorial {
 47
 48TCPSocketMessageProxyExample::TCPSocketMessageProxyExample() :
 49        MARTe::Object(), MARTe::EmbeddedServiceMethodBinderI(), tcpClientService(*this) {
 50    waitForConnection = true;
 51    mux.Create();
 52    timeout = 10;
 53
 54}
 55
 56TCPSocketMessageProxyExample::~TCPSocketMessageProxyExample() {
 57    using namespace MARTe;
 58    if (tcpClientService.Stop() != ErrorManagement::NoError) {
 59        if (tcpClientService.Stop() != ErrorManagement::NoError) {
 60            REPORT_ERROR(ErrorManagement::Warning, "Could not Stop the tcpThreadService");
 61        }
 62    }
 63    mux.UnLock();
 64    mux.Close();
 65    if (!socket.Close()) {
 66        REPORT_ERROR(ErrorManagement::Warning, "Could not Close the socket");
 67    }
 68}
 69
 70bool TCPSocketMessageProxyExample::Initialise(MARTe::StructuredDataI & data) {
 71    using namespace MARTe;
 72    uint32 port;
 73    bool ok = Object::Initialise(data);
 74    if (ok) {
 75        ok = data.Read("Port", port);
 76        if (!ok) {
 77            REPORT_ERROR(ErrorManagement::ParametersError, "Could not Read the Port parameter");
 78        }
 79    }
 80    if (ok) {
 81        ok = socket.Open();
 82        if (!ok) {
 83            REPORT_ERROR(ErrorManagement::ParametersError, "Could not Open server socket");
 84        }
 85    }
 86    if (ok) {
 87        ok = socket.Listen(port);
 88        if (!ok) {
 89            REPORT_ERROR(ErrorManagement::ParametersError, "Could not Listen on port %d", port);
 90        }
 91    }
 92    if (ok) {
 93        tcpClientService.SetName(GetName());
 94        ok = (tcpClientService.Start() == ErrorManagement::NoError);
 95        if (!ok) {
 96            REPORT_ERROR(ErrorManagement::ParametersError, "Could not Start tcpClientService");
 97        }
 98    }
 99    if (ok) {
100        REPORT_ERROR(ErrorManagement::Information, "Server listening in port %d", port);
101    }
102    return ok;
103}
104
105MARTe::ErrorManagement::ErrorType TCPSocketMessageProxyExample::Execute(MARTe::ExecutionInfo & info) {
106    using namespace MARTe;
107    ErrorManagement::ErrorType err;
108
109    if (info.GetStageSpecific() == MARTe::ExecutionInfo::WaitRequestStageSpecific) {
110        mux.Lock();
111        if (waitForConnection) {
112            waitForConnection = false;
113            mux.UnLock();
114            BasicTCPSocket *client = socket.WaitConnection(timeout);
115            if (client != NULL_PTR(BasicTCPSocket *)) {
116                REPORT_ERROR(ErrorManagement::Information, "Connection accepted!");
117                mux.Lock();
118                waitForConnection = true;
119                info.SetThreadSpecificContext(reinterpret_cast<void *>(client));
120                err = ErrorManagement::NoError;
121                mux.UnLock();
122            }
123            else {
124                mux.Lock();
125                waitForConnection = true;
126                err = ErrorManagement::Timeout;
127                mux.UnLock();
128            }
129        }
130        else {
131            mux.UnLock();
132            MARTe::Sleep::MSec(timeout);
133            err = ErrorManagement::Timeout;
134        }
135    }
136    if (info.GetStageSpecific() == MARTe::ExecutionInfo::ServiceRequestStageSpecific) {
137        BasicTCPSocket *client = reinterpret_cast<BasicTCPSocket *>(info.GetThreadSpecificContext());
138        if (client != NULL_PTR(BasicTCPSocket *)) {
139            const uint32 BUFFER_SIZE = 1024u;
140            char8 buffer[BUFFER_SIZE];
141            uint32 readBytes = BUFFER_SIZE;
142            MemoryOperationsHelper::Set(&buffer[0], '\0', BUFFER_SIZE);
143            if (client->Read(&buffer[0], readBytes)) {
144                StreamString configurationCfg = buffer;
145                REPORT_ERROR(ErrorManagement::ParametersError, "Received configuration message [size=%d]:%s", readBytes, configurationCfg.Buffer());
146                //Try to parse the configuration message
147                StreamString err;
148                //Force the string to be seeked to the beginning.
149                configurationCfg.Seek(0LLU);
150                ConfigurationDatabase msgCdb;
151                StandardParser parser(configurationCfg, msgCdb, &err);
152                ReferenceT<Message> msg(GlobalObjectsDatabase::Instance()->GetStandardHeap());
153                ErrorManagement::ErrorType msgError;
154                msgError.parametersError = !parser.Parse();
155                if (msgError.ErrorsCleared()) {
156                    //After parsing the tree is pointing at the last leaf
157                    msgCdb.MoveToRoot();
158                    msgError.parametersError = !msg->Initialise(msgCdb);
159                    if (!msgError.ErrorsCleared()) {
160                        REPORT_ERROR(ErrorManagement::ParametersError, "Failed to initialise message");
161                    }
162                }
163                else {
164                    StreamString errPrint;
165                    errPrint.Printf("Failed to parse %s", err.Buffer());
166                    REPORT_ERROR(ErrorManagement::ParametersError, errPrint.Buffer());
167                }
168                if (msgError.ErrorsCleared()) {
169                    msgError = MessageI::SendMessage(msg, this);
170                    if (!msgError.ErrorsCleared()) {
171                        REPORT_ERROR(ErrorManagement::ParametersError, "Error while sending message to destination %s with function %s",
172                                     msg->GetDestination().GetList(), msg->GetFunction().GetList());
173                    }
174                }
175                readBytes = BUFFER_SIZE;
176            }
177            if (!client->Close()) {
178                REPORT_ERROR(ErrorManagement::ParametersError, "Failed to Close client connection");
179            }
180            delete client;
181        }
182        return MARTe::ErrorManagement::Completed;
183    }
184    return err;
185}
186
187CLASS_REGISTER(TCPSocketMessageProxyExample, "")
188}

Start the application with the -m parameter.

In order to change state, start the application and, in another console, type echo -e "Destination=StateMachine\nFunction=GOTOSTATE2" | nc 127.0.0.1 24680.

Multiple states configuration (Run with NAME_OF_THE_MESSAGE=StateMachine:START and NAME_OF_THE_CONFIGURATION_FILE=RTApp-3.cfg)
  1+TCPMessageProxy = {
  2    Class = TCPSocketMessageProxyExample
  3    Port = 24680
  4}
  5+StateMachine = {
  6    Class = StateMachine
  7    +INITIAL = {
  8        Class = ReferenceContainer
  9        +START = {
 10            Class = StateMachineEvent
 11            NextState = "STATE1"
 12            NextStateError = "ERROR"
 13            Timeout = 0
 14            +ChangeToState1Msg = {
 15                Class = Message
 16                Destination = TestApp
 17                Mode = ExpectsReply
 18                Function = PrepareNextState
 19                +Parameters = {
 20                    Class = ConfigurationDatabase
 21                    param1 = State1
 22                }
 23            }
 24            +StartNextStateExecutionMsg = {
 25                Class = Message
 26                Destination = TestApp
 27                Function = StartNextStateExecution
 28                Mode = ExpectsReply
 29            }
 30        }
 31    }
 32    +STATE1 = {
 33        Class = ReferenceContainer
 34        +GOTOSTATE2 = {
 35            Class = StateMachineEvent
 36            NextState = "STATE2"
 37            NextStateError = "ERROR"
 38            Timeout = 0
 39            +PrepareChangeToState2Msg = {
 40                Class = Message
 41                Destination = TestApp
 42                Mode = ExpectsReply
 43                Function = PrepareNextState
 44                +Parameters = {
 45                    Class = ConfigurationDatabase
 46                    param1 = State2
 47                }
 48            }
 49            +StopCurrentStateExecutionMsg = {
 50                Class = Message
 51                Destination = TestApp
 52                Function = StopCurrentStateExecution
 53                Mode = ExpectsReply
 54            }
 55            +StartNextStateExecutionMsg = {
 56                Class = Message
 57                Destination = TestApp
 58                Function = StartNextStateExecution
 59                Mode = ExpectsReply
 60            }
 61        }
 62        +ERROR = {
 63            Class = StateMachineEvent
 64            NextState = "ERROR"
 65            NextStateError = "ERROR"
 66        }
 67    }
 68    +STATE2 = {
 69        Class = ReferenceContainer
 70        +GOTOSTATE1 = {
 71            Class = StateMachineEvent
 72            NextState = "STATE1"
 73            NextStateError = "ERROR"
 74            Timeout = 0
 75            +PrepareChangeToState1Msg = {
 76                Class = Message
 77                Destination = TestApp
 78                Mode = ExpectsReply
 79                Function = PrepareNextState
 80                +Parameters = {
 81                    Class = ConfigurationDatabase
 82                    param1 = State1
 83                }
 84            }
 85            +StopCurrentStateExecutionMsg = {
 86                Class = Message
 87                Destination = TestApp
 88                Function = StopCurrentStateExecution
 89                Mode = ExpectsReply
 90            }
 91            +StartNextStateExecutionMsg = {
 92                Class = Message
 93                Destination = TestApp
 94                Function = StartNextStateExecution
 95                Mode = ExpectsReply
 96            }
 97        }
 98        +ERROR = {
 99            Class = StateMachineEvent
100            NextState = "ERROR"
101            NextStateError = "ERROR"
102        }
103    }
104    +ERROR = {
105        Class = ReferenceContainer
106        +ENTER = {
107            Class = ReferenceContainer
108            +StopCurrentStateExecutionMsg = {
109                Class = Message
110                Destination = TestApp
111                Function = StopCurrentStateExecution
112                Mode = ExpectsReply
113            }
114            +PrepareChangeToErrorMsg = {
115                Class = Message
116                Destination = TestApp
117                Mode = ExpectsReply
118                Function = PrepareNextState
119                +Parameters = {
120                    Class = ConfigurationDatabase
121                    param1 = StateError
122                }
123            }
124            +StartNextStateExecutionMsg = {
125                Class = Message
126                Destination = TestApp
127                Function = StartNextStateExecution
128                Mode = ExpectsReply
129            }
130        }
131        +RESET = {
132            Class = StateMachineEvent
133            NextState = "STATE1"
134            NextStateError = "STATE1"
135            Timeout = 0
136            +StopCurrentStateExecutionMsg = {
137                Class = Message
138                Destination = TestApp
139                Function = StopCurrentStateExecution
140                Mode = ExpectsReply
141            }
142            +PrepareChangeToState1Msg = {
143                Class = Message
144                Destination = TestApp
145                Mode = ExpectsReply
146                Function = PrepareNextState
147                +Parameters = {
148                    Class = ConfigurationDatabase
149                    param1 = State1
150                }
151            }
152            +StartNextStateExecutionMsg = {
153                Class = Message
154                Destination = TestApp
155                Function = StartNextStateExecution
156                Mode = ExpectsReply
157            }
158        }
159    }
160}
161$TestApp = {
162    Class = RealTimeApplication
163    +Functions = {
164        Class = ReferenceContainer
165        +GAMTimer = {
166            Class = IOGAM
167            InputSignals = {
168                Counter = {
169                    DataSource = Timer
170                    Type = uint32
171                }
172                Time = {
173                    Frequency = 1
174                    DataSource = Timer
175                    Type = uint32
176                }
177            }
178            OutputSignals = {
179                Counter = {
180                    DataSource = DDB1
181                    Type = uint32
182                }
183                Time = {
184                    DataSource = DDB1
185                    Type = uint32
186                }
187            }
188        }
189        +GAMVariable1 = {
190            Class = VariableGAMExample1
191            Gains = {2, 3, 4}
192            InputSignals = {
193                Counter = {
194                    DataSource = DDB1
195                    Type = uint32
196                }                
197            }
198            OutputSignals = {
199                GainCounter1Thread1 = {
200                    DataSource = DDB1
201                    Type = uint32
202                }
203                GainCounter2Thread1 = {
204                    DataSource = DDB1
205                    Type = uint32
206                }
207                GainCounter3Thread1 = {
208                    DataSource = DDB1
209                    Type = uint32
210                }                
211            }
212        }
213        +GAMT1TSynchOut = {
214            Class = IOGAM
215            InputSignals = {
216                GainCounter1Thread1 = {
217                    DataSource = DDB1
218                    Type = uint32
219                }
220                GainCounter2Thread1 = {
221                    DataSource = DDB1
222                    Type = uint32
223                }
224                GainCounter3Thread1 = {
225                    DataSource = DDB1
226                    Type = uint32
227                }
228            }
229            OutputSignals = {
230                GainCounter1Thread1 = {
231                    DataSource = RTThreadSynch
232                    Type = uint32
233                }
234                GainCounter2Thread1 = {
235                    DataSource = RTThreadSynch
236                    Type = uint32
237                }
238                GainCounter3Thread1 = {
239                    DataSource = RTThreadSynch
240                    Type = uint32
241                }
242            }
243        }
244        +GAMT1T2Interface = {
245            Class = IOGAM
246            InputSignals = {
247                GainCounter1Thread1 = {
248                    DataSource = RTThreadSynch
249                    Type = uint32
250                    Samples = 2 //Run at half the frequency of thread 1
251                }
252                GainCounter2Thread1 = {
253                    DataSource = RTThreadSynch
254                    Type = uint32
255                    Samples = 2 //Run at half the frequency of thread 1
256                }
257                GainCounter3Thread1 = {
258                    DataSource = RTThreadSynch
259                    Type = uint32
260                    Samples = 2 //Run at half the frequency of thread 1
261                }
262            }
263            OutputSignals = {
264                GainCounter1Thread2 = {
265                    DataSource = DDB1
266                    Type = uint32
267                    Samples = 1
268                    NumberOfDimensions = 1
269                    NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
270                }
271                GainCounter2Thread2 = {
272                    DataSource = DDB1
273                    Type = uint32
274                    Samples = 1
275                    NumberOfDimensions = 1
276                    NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
277                }
278                GainCounter3Thread2 = {
279                    DataSource = DDB1
280                    Type = uint32
281                    Samples = 1
282                    NumberOfDimensions = 1
283                    NumberOfElements = 2 //2 elements for each cycle (as it waits for 2 samples)
284                }
285            }
286        }
287        +GAMT1T3Interface = {
288            Class = IOGAM
289            InputSignals = {
290                GainCounter1Thread1 = {
291                    DataSource = RTThreadSynch
292                    Type = uint32
293                    Samples = 4 //Run at one quarter of the frequency of thread 1
294                }
295                GainCounter2Thread1 = {
296                    DataSource = RTThreadSynch
297                    Type = uint32
298                    Samples = 4 //Run at one quarter  the frequency of thread 1
299                }
300                GainCounter3Thread1 = {
301                    DataSource = RTThreadSynch
302                    Type = uint32
303                    Samples = 4 //Run at one quarter  the frequency of thread 1
304                }
305            }
306            OutputSignals = {
307                GainCounter1Thread3 = {
308                    DataSource = DDB1
309                    Type = uint32
310                    Samples = 1
311                    NumberOfDimensions = 1
312                    NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
313                }
314                GainCounter2Thread3 = {
315                    DataSource = DDB1
316                    Type = uint32
317                    Samples = 1
318                    NumberOfDimensions = 1
319                    NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
320                }
321                GainCounter3Thread3 = {
322                    DataSource = DDB1
323                    Type = uint32
324                    Samples = 1
325                    NumberOfDimensions = 1
326                    NumberOfElements = 4 //4 elements for each cycle (as it waits for 4 samples)
327                }
328            }
329        }
330        +GAMDisplayThread1 = {
331            Class = IOGAM            
332            InputSignals = {
333                Counter = {
334                    DataSource = DDB1
335                    Type = uint32
336                }
337                GainCounter1Thread1 = {
338                    DataSource = DDB1
339                    Type = uint32
340                }
341                GainCounter2Thread1 = {
342                    DataSource = DDB1
343                    Type = uint32
344                }
345                GainCounter3Thread1 = {
346                    DataSource = DDB1
347                    Type = uint32
348                }            
349            }
350            OutputSignals = {
351                Counter = {
352                    DataSource = LoggerDataSource
353                    Type = uint32
354                }
355                GainCounter1Thread1 = {
356                    DataSource = LoggerDataSource
357                    Type = uint32
358                }
359                GainCounter2Thread1 = {
360                    DataSource = LoggerDataSource
361                    Type = uint32
362                }
363                GainCounter3Thread1 = {
364                    DataSource = LoggerDataSource
365                    Type = uint32
366                }
367            }
368        }
369        +GAMDisplayThread2 = {
370            Class = IOGAM            
371            InputSignals = {
372                GainCounter1Thread2 = {
373                    DataSource = DDB1
374                    Type = uint32
375                }
376                GainCounter2Thread2 = {
377                    DataSource = DDB1
378                    Type = uint32
379                }
380                GainCounter3Thread2 = {
381                    DataSource = DDB1
382                    Type = uint32
383                }            
384            }
385            OutputSignals = {
386                GainCounter1Thread2 = {
387                    DataSource = LoggerDataSource
388                    Type = uint32
389                    NumberOfDimensions = 1
390                    NumberOfElements = 2
391                }
392                GainCounter2Thread2 = {
393                    DataSource = LoggerDataSource
394                    Type = uint32
395                    NumberOfDimensions = 1
396                    NumberOfElements = 2
397                }
398                GainCounter3Thread2 = {
399                    DataSource = LoggerDataSource
400                    Type = uint32
401                    NumberOfDimensions = 1
402                    NumberOfElements = 2
403                }
404            }
405        }
406        +GAMDisplayThread3 = {
407            Class = IOGAM            
408            InputSignals = {
409                GainCounter1Thread3 = {
410                    DataSource = DDB1
411                    Type = uint32
412                }
413                GainCounter2Thread3 = {
414                    DataSource = DDB1
415                    Type = uint32
416                }
417                GainCounter3Thread3 = {
418                    DataSource = DDB1
419                    Type = uint32
420                }            
421            }
422            OutputSignals = {
423                GainCounter1Thread3 = {
424                    DataSource = LoggerDataSource
425                    Type = uint32
426                    NumberOfDimensions = 1
427                    NumberOfElements = 4
428                }
429                GainCounter2Thread3 = {
430                    DataSource = LoggerDataSource
431                    Type = uint32
432                    NumberOfDimensions = 1
433                    NumberOfElements = 4
434                }
435                GainCounter3Thread3 = {
436                    DataSource = LoggerDataSource
437                    Type = uint32
438                    NumberOfDimensions = 1
439                    NumberOfElements = 4
440                }
441            }
442        }
443    }
444    +Data = {
445        Class = ReferenceContainer
446        DefaultDataSource = DDB1
447        +DDB1 = {
448            Class = GAMDataSource
449        }
450        +LoggerDataSource = {
451            Class = LoggerDataSource
452        }
453        +Timings = {
454            Class = TimingDataSource
455        }
456        +RTThreadSynch = {
457            Class = RealTimeThreadSynchronisation
458            Timeout = 5000 //Timeout in ms to wait for the thread to cycle.
459        }
460        +Timer = {
461            Class = LinuxTimer
462            SleepNature = "Default"
463            Signals = {
464                Counter = {
465                    Type = uint32
466                }
467                Time = {
468                    Type = uint32
469                }
470            }
471        }
472    }
473    +States = {
474        Class = ReferenceContainer
475        +State1 = {
476            Class = RealTimeState
477            +Threads = {
478                Class = ReferenceContainer
479                +Thread1 = {
480                    Class = RealTimeThread
481                    CPUs = 0x1
482                    Functions = {GAMTimer GAMVariable1 GAMT1TSynchOut GAMDisplayThread1}
483                }
484            }
485        }
486        +State2 = {
487            Class = RealTimeState
488            +Threads = {
489                Class = ReferenceContainer
490                +Thread1 = {
491                    Class = RealTimeThread
492                    CPUs = 0x1
493                    Functions = {GAMTimer GAMVariable1 GAMT1TSynchOut GAMDisplayThread1}
494                }
495                +Thread2 = {
496                    Class = RealTimeThread
497                    CPUs = 0x2
498                    Functions = {GAMT1T2Interface GAMDisplayThread2}
499                }
500                +Thread3 = {
501                    Class = RealTimeThread
502                    CPUs = 0x4
503                    Functions = {GAMT1T3Interface GAMDisplayThread3}
504                }
505            }
506        }
507        +StateError = {
508            Class = RealTimeState
509            +Threads = {
510                Class = ReferenceContainer
511                +Thread1 = {
512                    Class = RealTimeThread
513                    CPUs = 0x1
514                    Functions = {GAMTimer}
515                }
516            }
517        }
518    }
519    +Scheduler = {
520        Class = GAMScheduler
521        TimingDataSource = Timings
522    }
523}

Instructions on how to compile and execute the examples can be found here.