7.3.1. Binary: Mirror#
Under this section you will find a simple example of a client/server application using the eCAL ClientServer API. You should be already familiar with the base handling of eCAL from the Publisher/Subscriber samples, so this we will not be covered in detail any more.
7.3.1.1. Mirror Server#
A service server is an eCAL instance that is matched to service client instances by their name. It can offer multiple methods, which a connected service client can call. We will set up a simple server that provides two methods: “echo” and “mirror”.
The main process is:
Intialize eCAL
Create a Service Server
For each method, add meta information about that method (such as method name, and types of the request and response) and a callback function to be invoked, when a client calls that method
Keep the program running while the service is supposed to be executed
1#include <ecal/ecal.h>
2
3#include <algorithm>
4#include <iostream>
5#include <chrono>
6#include <thread>
7
8void printCallbackInformation(const eCAL::SServiceMethodInformation& method_info_, const std::string& request_, const std::string& response_)
9{
10 std::cout << "Method : '" << method_info_.method_name << "' called in C++" << "\n";
11 std::cout << "Request : " << request_ << "\n";
12 std::cout << "Response : " << response_ << "\n";
13 std::cout << "\n";
14}
15
16/*
17 We define the callback function that will be called when a client calls the service method "echo".
18 This callback will simply return the request as the response.
19*/
20int OnEchoCallback(const eCAL::SServiceMethodInformation& method_info_, const std::string& request_, std::string& response_)
21{
22 response_ = request_;
23
24 printCallbackInformation(method_info_, request_, response_);
25
26 // The return value here has no actual meaning. It's made available to the caller.
27 return 0;
28}
29
30/*
31 This callback will be called when a client calls the service method "reverse".
32 It will return the request in reverse order as the response.
33*/
34int OnReverseCallback(const eCAL::SServiceMethodInformation& method_info_, const std::string& request_, std::string& response_)
35{
36 response_.resize(request_.size());
37 std::copy(request_.rbegin(), request_.rend(), response_.begin());
38
39 printCallbackInformation(method_info_, request_, response_);
40
41 // The return value here has no actual meaning. It's made available to the caller.
42 return 0;
43}
44
45int main()
46{
47 std::cout << "--------------------" << "\n";
48 std::cout << " C++: MIRROR SERVER" << "\n";
49 std::cout << "--------------------" << "\n";
50
51 /*
52 As always: initialize the eCAL API and give your process a name.
53 */
54 eCAL::Initialize("mirror server");
55
56 std::cout << "eCAL " << eCAL::GetVersionString() << " (" << eCAL::GetVersionDateString() << ")" << "\n";
57 eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "I feel good!");
58
59 /*
60 Now we create the mirror server and give it the name "mirror".
61 */
62 eCAL::CServiceServer mirror_server("mirror");
63
64 /*
65 The server will have two methods: "echo" and "reverse".
66 To set a callback, we need to set a ServiceMethodInformation struct as well as the callback function.
67 We simplify the struct creation of ServiceMethodInformationStruct and the other two
68 fields can be left empty for our example.
69 */
70 mirror_server.SetMethodCallback({ "echo", {}, {} }, OnEchoCallback);
71 mirror_server.SetMethodCallback({ "reverse", {}, {} }, OnReverseCallback);
72
73 /*
74 Now we will go in an infinite loop, to wait for incoming service calls that will be handled with the callbacks.
75 */
76 while(eCAL::Ok())
77 {
78 std::this_thread::sleep_for(std::chrono::milliseconds(500));
79 }
80
81 /*
82 After we are done, as always, finalize the eCAL API.
83 */
84 eCAL::Finalize();
85
86 return(0);
87}
1#include <ecal_c/ecal.h>
2
3#include <stdio.h> //printf()
4#include <string.h> //memcpy(), memset()
5
6void printCallbackInformation(const struct eCAL_SServiceMethodInformation* method_info_, const char* request_, size_t request_length_, const char* response_, size_t* response_length_)
7{
8 /*
9 The data we get will not be \0 terminated. Hence we need to pass the size to printf.
10 */
11 printf("Method : '%s' called in C\n", method_info_->method_name);
12 printf("Request : %.*s\n", (int)request_length_, request_);
13 printf("Response : %.*s\n", (int)*response_length_, response_);
14 printf("\n");
15}
16
17/*
18 We define the callback function that will be called when a client calls the service method "echo".
19 This callback will simply return the request as the response.
20*/
21int OnEchoCallback(const struct eCAL_SServiceMethodInformation* method_info_, const void* request_, size_t request_length_, void** response_, size_t* response_length_, void* user_argument_)
22{
23 (void)user_argument_;
24
25 /*
26 In order pass the server response properly to the callback API, the underlying memory needs to be allocated
27 with eCAL_Malloc(). The allocation via eCAL_Malloc() is required as the internal memory handler frees the
28 resevered memory after callback execution.
29 */
30 *response_ = eCAL_Malloc(request_length_);
31
32 /*
33 In case of a failure, the value that response_ points to, remains NULL.
34 */
35 if (*response_ == NULL) return -1; // memory allocation failed
36
37 /*
38 The length of response buffer needs to be set accordingly
39 */
40 *response_length_ = request_length_;
41 /*
42 In this example the entire request buffer will be copied over to the response buffer.
43 */
44 memcpy(*response_, request_, request_length_);
45
46 printCallbackInformation(method_info_, (const char*)request_, request_length_, (const char*)(*response_), response_length_);
47
48 return 0;
49}
50
51/*
52 This callback will be called when a client calls the service method "reverse".
53 It will return the request in reverse order as the response.
54*/
55int OnReverseCallback(const struct eCAL_SServiceMethodInformation* method_info_, const void* request_, size_t request_length_, void** response_, size_t* response_length_, void* user_argument_)
56{
57 (void)user_argument_;
58
59 /*
60 In order pass the server response properly to the callback API, the underlying memory needs to be allocated
61 with eCAL_Malloc(). The allocation via eCAL_Malloc() is required as the internal memory handler frees the
62 resevered memory after callback execution.
63 */
64 *response_ = eCAL_Malloc(request_length_);
65
66 /*
67 In case of a failure, the value that response_ points to, remains NULL.
68 */
69 if (*response_ == NULL) return -1; // memory allocation failed
70
71 /*
72 The length of response buffer needs to be set accordingly
73 */
74 *response_length_ = request_length_;
75
76 const char* request = (const char*)request_;
77 char* response = (char*)(*response_);
78
79 for (size_t i = 0; i < request_length_; ++i) {
80 response[i] = request[request_length_ - 1 - i];
81 }
82
83 printCallbackInformation(method_info_, (const char*)request_, request_length_, (const char*)(*response_), response_length_);
84
85 return 0;
86}
87
88int main()
89{
90 printf("------------------\n");
91 printf(" C: Mirror Server\n");
92 printf("------------------\n");
93
94 /*
95 Here we already create the objects we want to work with.
96 Later we will create the server handle and fill the ServiceMethodInformation struct with the required information.
97 */
98 eCAL_ServiceServer *mirror_server;
99 struct eCAL_SServiceMethodInformation echo_method_information;
100 struct eCAL_SServiceMethodInformation reverse_method_information;
101
102 /*
103 As always: initialize the eCAL API and give your process a name.
104 */
105 eCAL_Initialize("mirror server c", NULL, NULL);
106
107 printf("eCAL %s (%s)\n", eCAL_GetVersionString(), eCAL_GetVersionDateString());
108 eCAL_Process_SetState(eCAL_Process_eSeverity_healthy, eCAL_Process_eSeverityLevel_level1, "I feel good!");
109
110 /*
111 Now we create the mirror server and give it the name "mirror".
112 */
113 mirror_server = eCAL_ServiceServer_New("mirror", NULL);
114
115 /*
116 The server will have two methods: "echo" and "reverse".
117 To set a callback, we need to set a ServiceMethodInformation struct as well as the callback function.
118 In our example we will just set the method name of the struct and leave the other two fields empty.
119 */
120 memset(&echo_method_information, 0, sizeof(struct eCAL_SServiceMethodInformation));
121 echo_method_information.method_name = "echo";
122 eCAL_ServiceServer_SetMethodCallback(mirror_server, &echo_method_information, OnEchoCallback, NULL);
123
124 memset(&reverse_method_information, 0, sizeof(struct eCAL_SServiceMethodInformation));
125 reverse_method_information.method_name = "reverse";
126 eCAL_ServiceServer_SetMethodCallback(mirror_server, &reverse_method_information, OnReverseCallback, NULL);
127
128 /*
129 Now we will go in an infinite loop, to wait for incoming service calls that will be handled with the callbacks.
130 */
131 while (eCAL_Ok())
132 {
133 eCAL_Process_SleepMS(500);
134 }
135
136 /*
137 When finished, we need to delete the server handle to clean up properly.
138 */
139 eCAL_ServiceServer_Delete(mirror_server);
140
141 /*
142 After we are done, as always, finalize the eCAL API.
143 */
144 eCAL_Finalize();
145
146 return 0;
147}
1using System;
2using System.Text;
3using Eclipse.eCAL.Core;
4
5public class MirrorServer
6{
7 static void PrintCallbackInformation(string method, byte[] request, byte[] response)
8 {
9 Console.WriteLine("Method : '" + method + "' called in C#");
10 Console.WriteLine("Request : " + Encoding.UTF8.GetString(request));
11 Console.WriteLine("Response : " + Encoding.UTF8.GetString(response));
12 Console.WriteLine();
13 }
14
15 /*
16 We define the callback function that will be called when a client calls the service method "echo".
17 This callback will simply return the request as the response.
18 */
19 static byte[] OnEchoCallback(ServiceMethodInformation methodInfo, byte[] request)
20 {
21 byte[] response = request;
22
23 PrintCallbackInformation(methodInfo.MethodName, request, response);
24
25 return response;
26 }
27
28 /*
29 This callback will be called when a client calls the service method "reverse".
30 It will return the request in reverse order as the response.
31 */
32 static byte[] OnReverseCallback(ServiceMethodInformation methodInfo, byte[] request)
33 {
34 byte[] response = (byte[])request.Clone();
35 Array.Reverse(response);
36
37 PrintCallbackInformation(methodInfo.MethodName, request, response);
38
39 return response;
40 }
41
42 static void Main()
43 {
44 Console.WriteLine("-------------------");
45 Console.WriteLine(" C#: MIRROR SERVER");
46 Console.WriteLine("-------------------");
47
48 /*
49 As always: initialize the eCAL API and give your process a name.
50 */
51 Core.Initialize("mirror server c#");
52
53 Console.WriteLine(string.Format("eCAL {0} ({1})\n", Core.GetVersionString(), Core.GetVersionDateString()));
54
55 /*
56 Now we create the mirror server and give it the name "mirror".
57 */
58 ServiceServer mirrorServer = new ServiceServer("mirror");
59
60 /*
61 The server will have two methods: "echo" and "reverse".
62 To set a callback, we need to set a ServiceMethodInformation struct as well as the callback function.
63 In our example we will just set the method name of the struct and leave the other two fields empty.
64 */
65 ServiceMethodInformation echoMethodInfo = new ServiceMethodInformation();
66 echoMethodInfo.MethodName = "echo";
67 mirrorServer.SetMethodCallback(echoMethodInfo, OnEchoCallback);
68
69 ServiceMethodInformation reverseMethodInfo = new ServiceMethodInformation();
70 reverseMethodInfo.MethodName = "reverse";
71 mirrorServer.SetMethodCallback(reverseMethodInfo, OnReverseCallback);
72
73 /*
74 Now we will go in an infinite loop, to wait for incoming service calls that will be handled with the callbacks.
75 */
76 while (Core.Ok())
77 {
78 System.Threading.Thread.Sleep(500);
79 }
80
81 /*
82 When finished, we need to dispose the server to clean up properly.
83 */
84 mirrorServer.Dispose();
85
86 /*
87 After we are done, as always, finalize the eCAL API.
88 */
89 Core.Terminate();
90 }
91}
1import time
2import textwrap
3from typing import Tuple
4
5import ecal.nanobind_core as ecal_core
6
7def print_data(method_name : str, request : bytes, response : bytes):
8 print(f"Method : '{method_name}' called in Python")
9 print(f"Requests : {request}")
10 print(f"Response : {response}")
11 print()
12
13# Define the callback function that will be called when a client calls the service method "echo".
14def echo_req_callback(
15 method_information : ecal_core.ServiceMethodInformation,
16 request : bytes) -> Tuple[int, bytes]:
17 response = request
18 print_data(method_information.method_name, request, response)
19 return 0, response
20
21# Define the callback function that will be called when a client calls the service method "reverse".
22def reverse_req_callback(
23 method_information : ecal_core.ServiceMethodInformation,
24 request : bytes) -> Tuple[int, bytes]:
25 response = request[::-1] #reverse the request
26 print_data(method_information.method_name, request, response)
27 return 0, response
28
29def main():
30 print(textwrap.dedent("""
31 -----------------------
32 Python: MIRROR SERVER
33 -----------------------
34 """).strip())
35
36 # First, initialize the eCAL API.
37 ecal_core.initialize("mirror server python")
38
39 # Print eCAL version and date.
40 print(f"eCAL {ecal_core.get_version_string()} ({ecal_core.get_version_date_string()})")
41 ecal_core.process.set_state(ecal_core.process.Severity.HEALTHY, ecal_core.process.SeverityLevel.LEVEL1, "I feel good");
42
43 # Create the mirror server and give it the name "mirror".
44 server = ecal_core.ServiceServer("mirror")
45
46 # The server will have two methods: "echo" and "reverse".
47 # To set a callback, we need to set a ServiceMethodInformation struct as well as the callback function.
48 echo_method_info = ecal_core.ServiceMethodInformation(method_name="echo")
49 server.set_method_callback(echo_method_info, echo_req_callback)
50 reverse_method_info = ecal_core.ServiceMethodInformation(method_name="reverse")
51 server.set_method_callback(reverse_method_info, reverse_req_callback)
52
53 # We can retrieve the services name / id.
54 print(server.get_service_name())
55 print(server.get_service_id())
56
57 # We can check if clients have connected to this service.
58 print(server.is_connected())
59
60 # Now we will go in an infinite loop, to wait for incoming service calls that will be handled with the callbacks.
61 while(ecal_core.ok()):
62 time.sleep(0.1)
63
64 # destroy server
65 server.destroy()
66
67 # finalize eCAL API
68 server.finalize()
69
70if __name__ == "__main__":
71 main()
1import sys
2import time
3
4import ecal.core.core as ecal_core
5import ecal.core.service as ecal_service
6
7def main():
8 # print eCAL version and date
9 print("eCAL {} ({})\n".format(ecal_core.getversion(), ecal_core.getdate()))
10
11 # initialize eCAL API
12 ecal_core.initialize("py_minimal_service_server")
13
14 # set process state
15 ecal_core.set_process_state(1, 1, "I feel good")
16
17 # create a server for the "DemoService" service
18 server = ecal_service.Server("DemoService")
19
20 # define the server method "foo" function
21 def foo_req_callback(method_name, req_type, resp_type, request):
22 print("'DemoService' method '{}' called with {}".format(method_name, request))
23 return 0, bytes("thank you for calling foo :-)", "ascii")
24
25 # define the server method "ping" function
26 def ping_req_callback(method_name, req_type, resp_type, request):
27 print("'DemoService' method '{}' called with {}".format(method_name, request))
28 return 0, bytes("pong", "ascii")
29
30 # define the server methods and connect them to the callbacks
31 server.add_method_callback("foo", "string", "string", foo_req_callback)
32 server.add_method_callback("ping", "ping_type", "pong_type", ping_req_callback)
33
34 # idle
35 while(ecal_core.ok()):
36 time.sleep(1.0)
37
38 # destroy server
39 server.destroy()
40
41 # finalize eCAL API
42 ecal_core.finalize()
43
44if __name__ == "__main__":
45 main()
├─ C++ │ └─mirror_server.cpp│ ├─ C │ └─mirror_server.c│ ├─ C# │ └─mirror_server.cs│ ├─ Python │ └─mirror_server.py│ └─ Python (legacy) └─mirror_server.py
7.3.1.2. Mirror Client#
The client will have some more logic to take care of, as its possible that multiple servers are running with the same service name.
Initialize eCAL
Create a service client with the service name and (optionally) register the functions it can call (in this case “echo” and “mirror”)
Waiting for a server to be available (this is optional and depends on how you want to design your application)
Retrieve all client instances. You can also call it directly on the service client, but if you iterate through all client instances, you are more flexible and could filter out instances you don’t want to call.
Then we call the methodnames with two different calls: with callback (non blocking) and with response (blocking)
Handle the received data (or error status)
As a little extra we also added a little bit more eCAL state handling as in the previous examples.
1#include <ecal/ecal.h>
2
3#include <iostream>
4#include <chrono>
5#include <thread>
6
7/*
8 Helper function to print the service response.
9*/
10void printServiceResponse(const eCAL::SServiceResponse& service_response_)
11{
12 std::string call_state;
13 switch (service_response_.call_state)
14 {
15 case eCAL::eCallState::executed:
16 call_state = "EXECUTED";
17 break;
18 case eCAL::eCallState::failed:
19 call_state = "FAILED";
20 break;
21 default:
22 call_state = "UNKNOWN";
23 break;
24 }
25
26 std::cout << "Received service response in C++: " << call_state << "\n";
27 std::cout << "Method : " << service_response_.service_method_information.method_name << "\n";
28 std::cout << "Response : " << service_response_.response << "\n";
29 std::cout << "Server ID : " << service_response_.server_id.service_id.entity_id << "\n";
30 std::cout << "Host : " << service_response_.server_id.service_id.host_name << "\n";
31 std::cout << "\n";
32}
33
34int main()
35{
36 std::cout << "--------------------" << "\n";
37 std::cout << " C++: MIRROR CLIENT" << "\n";
38 std::cout << "--------------------" << "\n";
39
40 /*
41 As always: initialize the eCAL API and give your process a name.
42 */
43 eCAL::Initialize("mirror client c++");
44
45 std::cout << "eCAL " << eCAL::GetVersionString() << " (" << eCAL::GetVersionDateString() << ")" << "\n";
46 eCAL::Process::SetState(eCAL::Process::eSeverity::warning, eCAL::Process::eSeverityLevel::level1, "Waiting for a service ...");
47
48 /*
49 Create a client that connects to a "mirror" server.
50 It may call the methods "echo" and "reverse"
51 */
52 const eCAL::CServiceClient mirror_client("mirror", { {"echo", {}, {} }, {"reverse", {}, {} } });
53
54 /*
55 This lambda serves as a callback which will be executed when we receive a response from a server.
56 */
57 auto service_response_callback = [](const eCAL::SServiceResponse& service_response_) {
58 printServiceResponse(service_response_);
59 };
60
61 /*
62 We wait until the client is connected to a server,
63 so we don't call methods that are not available.
64 */
65 while (!mirror_client.IsConnected())
66 {
67 std::cout << "Waiting for a service ..." << "\n";
68
69 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
70 }
71
72 /*
73 Now that we are connected, we can set the process state to "healthy" and communicate the connection.
74 */
75 eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Connected!");
76
77 /*
78 Allow to alternate between the two methods "echo" and "reverse".
79 */
80 unsigned int i = 0;
81 std::vector<std::string> methods = { "echo", "reverse" };
82 bool calls_ok = false;;
83
84 while(eCAL::Ok())
85 {
86 /*
87 Alternate between the two methods "echo" and "reverse".
88 Create the request payload.
89 */
90 std::string method_name = methods[i++ % methods.size()];
91 std::string request("stressed");
92
93 calls_ok = !mirror_client.GetClientInstances().empty();
94
95 /*
96 We iterate now over all client instances and call the methods by name.
97 With this approach we have the option to filter out client instances that we don't want to call.
98 If you want to call either way all instances, then you can use
99
100 mirror_client.CallWithResponse(...)
101 mirror_client.CallWithCallback(...)
102
103 instead of the loop.
104 */
105 for (auto& client_instance : mirror_client.GetClientInstances())
106 {
107 /*
108 Service call: blocking
109 We leave the default timeout value (infinite) for the blocking call.
110 You can change this for a specified timeout in ms.
111 */
112 const auto service_response = client_instance.CallWithResponse(method_name, request, eCAL::CClientInstance::DEFAULT_TIME_ARGUMENT);
113 if (std::get<0>(service_response))
114 {
115 const auto& response_content = std::get<1>(service_response);
116
117 printServiceResponse(response_content);
118 }
119 else
120 {
121 std::cout << "Method blocking call failed." << "\n";
122 calls_ok = false;
123 }
124
125 /*
126 Service call: with callback
127 The callback will be executed when the server has processed the request and sent a response.
128 You can again set a timeout value for an internal waiting time. By default, we wait infinitely.
129 */
130 if (!client_instance.CallWithCallback(method_name, request, service_response_callback, eCAL::CClientInstance::DEFAULT_TIME_ARGUMENT))
131 {
132 std::cout << "Method callback call failed." << "\n";
133 calls_ok = false;
134 }
135 }
136
137 /*
138 Now we set the process state according to the result of the service calls.
139 You will see the state in the eCAL Monitor or the eCAL Sys application.
140 */
141 if (calls_ok)
142 {
143 eCAL::Process::SetState(eCAL::Process::eSeverity::healthy, eCAL::Process::eSeverityLevel::level1, "Connected!");
144 }
145 else
146 {
147 eCAL::Process::SetState(eCAL::Process::eSeverity::critical, eCAL::Process::eSeverityLevel::level3, "Calls failed!");
148 }
149
150 std::this_thread::sleep_for(std::chrono::milliseconds(1000));
151 }
152
153 /*
154 After we are done, as always, finalize the eCAL API.
155 */
156 eCAL::Finalize();
157
158 return(0);
159}
1#include <ecal_c/ecal.h>
2#include <ecal_c/service/client.h>
3
4#include <stdio.h> // printf()
5#include <string.h> // strlen
6#include <stdlib.h> // free
7#include <inttypes.h> //uint64_t
8
9/*
10 Helper function to print the service response.
11*/
12void printServiceResponse(const struct eCAL_SServiceResponse* service_response)
13{
14 const char* call_state = NULL;
15
16 switch (service_response->call_state)
17 {
18 case eCAL_eCallState_executed:
19 call_state = "EXECUTED";
20 break;
21 case eCAL_eCallState_failed:
22 call_state = "FAILED";
23 break;
24 default:
25 call_state = "UNKNOWN";
26 break;
27 }
28
29 printf("Received service response in C: %s\n", call_state);
30 printf("Method : %s\n", service_response->service_method_information.method_name);
31 printf("Response : %.*s\n", (int)service_response->response_length, (char*)service_response->response);
32 printf("Server ID : %" PRIu64 "\n", service_response->server_id.service_id.entity_id);
33 printf("Host : %s\n", service_response->server_id.service_id.host_name);
34 printf("\n");
35}
36
37/*
38 Callback function that will be executed when we receive a response from a server.
39*/
40void serviceResponseCallback(const struct eCAL_SServiceResponse* service_response, void* user_data)
41{
42 (void)user_data;
43
44 printServiceResponse(service_response);
45}
46
47
48int main()
49{
50 eCAL_ServiceClient* mirror_client;
51 struct eCAL_SServiceMethodInformation* method_information_set;
52
53 printf("------------------\n");
54 printf(" C: MIRROR CLIENT\n");
55 printf("------------------\n");
56
57 /*
58 As always: initialize the eCAL API and give your process a name.
59 */
60 eCAL_Initialize("mirror client c", NULL, NULL);
61
62 printf("eCAL %s (%s)\n", eCAL_GetVersionString(), eCAL_GetVersionDateString());
63 eCAL_Process_SetState(eCAL_Process_eSeverity_healthy, eCAL_Process_eSeverityLevel_level1, "Waiting for a service ...");
64
65 /*
66 Create a ServiceMethodInformation struct that contains the information about the service methods we want to call.
67 In this case, we want to call the methods "echo" and "reverse".
68 */
69 method_information_set = (struct eCAL_SServiceMethodInformation*)eCAL_Malloc(2 * sizeof(struct eCAL_SServiceMethodInformation));
70 if (method_information_set == NULL)
71 {
72 printf("Memory allocation failed.\n");
73 return -1;
74 }
75
76 memset(method_information_set, 0, 2 * sizeof(struct eCAL_SServiceMethodInformation));
77 method_information_set[0].method_name = "echo";
78 method_information_set[1].method_name = "reverse";
79
80 /*
81 Create a client that connects to a "mirror" server.
82 It may call the methods "echo" and "reverse".
83 */
84 mirror_client = eCAL_ServiceClient_New("mirror", method_information_set, 0, NULL);
85
86 /*
87 Wait until the client is connected to a server,
88 so we don't call methods that are not available.
89 */
90 while (!eCAL_ServiceClient_IsConnected(mirror_client))
91 {
92 printf("Waiting for a service ...\n");
93 eCAL_Process_SleepMS(1000);
94 }
95
96 /*
97 Now that we are connected, we can set the process state to "healthy" and communicate the connection.
98 */
99 eCAL_Process_SetState(eCAL_Process_eSeverity_healthy, eCAL_Process_eSeverityLevel_level1, "Connected!");
100
101 /*
102 Allow alternating between the two methods "echo" and "reverse".
103 */
104 const char* methods[] = { "echo", "reverse" };
105 size_t method_count = sizeof(methods) / sizeof(methods[0]);
106 size_t i = 0;
107 unsigned int calls_ok = 0;
108
109 while (eCAL_Ok())
110 {
111 /*
112 Alternate between the two methods "echo" and "reverse".
113 Create the request payload.
114 */
115 const char* method_name = methods[i++ % method_count];
116 char request[] = "stressed";
117
118 struct eCAL_ClientInstance** client_instances = eCAL_ServiceClient_GetClientInstances(mirror_client);
119 calls_ok = client_instances != NULL && client_instances[0] != NULL;
120
121 /*
122 We iterate now over all client instances and call the methods by name.
123 With this approach we have the option to filter out client instances that we don't want to call.
124 If you want to call either way all instances, then you can use
125
126 eCAL_ServiceClient_CallWithResponse(mirror_client, ...)
127 eCAL_ServiceClient_CallWithCallback(mirror_client, ...)
128
129 instead of the loop.
130 */
131
132 if (client_instances != NULL)
133 {
134 for (size_t j = 0; client_instances[j] != NULL; ++j)
135 {
136 /*
137 Service call: blocking
138 We leave the default timeout value (infinite) for the blocking call.
139 You can change this for a specified timeout in ms.
140 */
141 struct eCAL_SServiceResponse* response = eCAL_ClientInstance_CallWithResponse(client_instances[j], method_name, request, strlen(request), NULL);
142 if (response != NULL)
143 {
144 printServiceResponse(response);
145 eCAL_Free(response);
146 }
147 else
148 {
149 printf("Method blocking call failed.\n");
150 calls_ok = 0;
151 }
152
153 /*
154 Service call: with callback
155 The callback will be executed when the server has processed the request and sent a response.
156 You can again set a timeout value for an internal waiting time. By default, we wait infinitely.
157 */
158 if(eCAL_ClientInstance_CallWithCallback(client_instances[j], method_name, request, strlen(request), serviceResponseCallback, NULL, NULL) != 0)
159 {
160 printf("Method callback call failed.\n");
161 calls_ok = 0;
162 }
163 }
164
165 /*
166 After usage, free the memory from the client instances.
167 */
168 eCAL_ClientInstances_Delete(client_instances);
169 }
170
171 /*
172 Now we set the process state according to the result of the service calls.
173 You will see the state in the eCAL Monitor or the eCAL Sys application.
174 */
175 if (calls_ok != 0)
176 {
177 eCAL_Process_SetState(eCAL_Process_eSeverity_healthy, eCAL_Process_eSeverityLevel_level1, "Connected!");
178 }
179 else
180 {
181 eCAL_Process_SetState(eCAL_Process_eSeverity_critical, eCAL_Process_eSeverityLevel_level3, "Calls failed!");
182 }
183
184 eCAL_Process_SleepMS(1000);
185 }
186
187 /*
188 Don't forget to delete the client handle.
189 */
190 eCAL_ServiceClient_Delete(mirror_client);
191
192 /*
193 After we are done, as always, finalize the eCAL API.
194 */
195 eCAL_Finalize();
196
197 return 0;
198}
1using System;
2using System.Collections.Generic;
3using System.Text;
4using Eclipse.eCAL.Core;
5
6public class MirrorClient
7{
8 /*
9 Helper function to print the service response.
10 */
11 static void PrintServiceResponse(ServiceResponse serviceResponse)
12 {
13 string callState;
14 switch (serviceResponse.CallState)
15 {
16 case CallState.Executed:
17 callState = "EXECUTED";
18 break;
19 case CallState.Failed:
20 callState = "FAILED";
21 break;
22 default:
23 callState = "UNKNOWN";
24 break;
25 }
26
27 Console.WriteLine("Received service response in C: " + callState);
28 Console.WriteLine("Method : " + serviceResponse.MethodInformation.MethodName);
29 Console.WriteLine("Response : " + Encoding.UTF8.GetString(serviceResponse.Response));
30 Console.WriteLine("Server ID : " + serviceResponse.ServerId.EntityID.Id);
31 Console.WriteLine("Host : " + serviceResponse.ServerId.EntityID.HostName);
32 Console.WriteLine();
33 }
34
35 static void Main()
36 {
37 Console.WriteLine("-------------------");
38 Console.WriteLine(" C#: MIRROR CLIENT");
39 Console.WriteLine("-------------------");
40
41 /*
42 As always: initialize the eCAL API and give your process a name.
43 */
44 Core.Initialize("mirror client c#");
45
46 Console.WriteLine(String.Format("eCAL {0} ({1})\n", Core.GetVersionString(), Core.GetVersionDateString()));
47
48 /*
49 Create a client that connects to a "mirror" server.
50 It may call the methods "echo" and "reverse"
51 */
52 ServiceMethodInformationList methodInformationList = new ServiceMethodInformationList();
53 methodInformationList.Methods.Add(new ServiceMethodInformation("echo", new DataTypeInformation(), new DataTypeInformation()));
54 methodInformationList.Methods.Add(new ServiceMethodInformation("reverse", new DataTypeInformation(), new DataTypeInformation()));
55
56 ServiceClient mirrorClient = new ServiceClient("mirror", methodInformationList);
57
58 /*
59 We wait until the client is connected to a server,
60 so we don't call methods that are not available.
61 */
62 while (!mirrorClient.IsConnected())
63 {
64 Console.WriteLine("Waiting for a service ...");
65 System.Threading.Thread.Sleep(1000);
66 }
67
68 /*
69 Allow to alternate between the two methods "echo" and "reverse".
70 */
71 int i = 0;
72 string[] methods = new string[] { "echo", "reverse" };
73
74 while (Core.Ok())
75 {
76 /*
77 Alternate between the two methods "echo" and "reverse".
78 Create the request payload.
79 */
80 string method = methods[i++ % methods.Length];
81 byte[] request = Encoding.UTF8.GetBytes("stressed");
82
83 /*
84 Service call with response
85 */
86 List<ServiceResponse> responseList = mirrorClient.CallWithResponse(method, request, (int)Eclipse.eCAL.Core.ServiceClient.DefaultTimeArgument);
87
88 /*
89 Iterate through all responses and print them.
90 */
91 if (responseList.Count > 0)
92 {
93 foreach (ServiceResponse response in responseList)
94 {
95 PrintServiceResponse(response);
96 }
97 }
98 else
99 {
100 Console.WriteLine("Method call with response failed.");
101 }
102
103 /*
104 Service call with callback
105 */
106 if (!mirrorClient.CallWithCallback(
107 method,
108 request,
109 response => PrintServiceResponse(response),
110 (int)ServiceClient.DefaultTimeArgument)
111 )
112 {
113 Console.WriteLine("Method call with callback failed.");
114 }
115
116 System.Threading.Thread.Sleep(1000);
117 }
118
119 /*
120 When finished, we need to dispose the client to clean up properly.
121 */
122 mirrorClient.Dispose();
123
124 /*
125 After we are done, as always, finalize the eCAL API.
126 */
127 Core.Terminate();
128 }
129}
1from pickle import TRUE
2import sys
3import textwrap
4import time
5
6import ecal.nanobind_core as ecal_core
7
8def print_service_response(service_response : ecal_core.ServiceResponse):
9 print(f"Received service response in Python: {service_response.call_state}")
10 print(f"Method : {service_response.service_method_information.method_name}")
11 print(f"Response : {service_response.response}")
12 print(f"Server ID : {service_response.server_id.service_id.entity_id}")
13 print(f"Host : {service_response.server_id.service_id.host_name}")
14 print()
15
16# generator, alternating returns "echo", "reverse"
17def generate_method_name():
18 methods = ["echo", "reverse"]
19 while True:
20 for method in methods:
21 yield method
22
23def main():
24 print(textwrap.dedent("""
25 -----------------------
26 Python: MIRROR CLIENT
27 -----------------------
28 """).strip())
29
30 # First, initialize the eCAL API.
31 ecal_core.initialize("mirror client python")
32
33 # Print eCAL version and date.
34 print(f"eCAL {ecal_core.get_version_string()} ({ecal_core.get_version_date_string()})")
35 ecal_core.process.set_state(ecal_core.process.Severity.WARNING, ecal_core.process.SeverityLevel.LEVEL1, "Waiting for a server");
36
37 # Create a client for the "mirror" service
38 mirror_client = ecal_core.ServiceClient("mirror")
39
40 # Wait until the client is connected to a server,
41 # so we don't call methods that are not available.
42 while (not mirror_client.is_connected()):
43 print("Waiting for a service ...")
44 time.sleep(1.0)
45
46 # Now that we are connected, we can set the process state to "healthy" and communicate the connection.
47 ecal_core.process.set_state(ecal_core.process.Severity.HEALTHY, ecal_core.process.SeverityLevel.LEVEL1, "Connected!");
48
49 # instantiate the generator to switch between calls to "echo" and "reverse".
50 method_generator = generate_method_name()
51
52 # idle and call service methods
53 while(ecal_core.ok()):
54
55 # We iterate now over all client instances and call the methods by name.
56 # With this approach we have the option to filter out client instances that we don't want to call.
57
58 service_request = bytes("stressed", "ascii")
59 service_method_name = next(method_generator)
60
61 client_instances = mirror_client.get_client_instances()
62 for client_instance in client_instances:
63
64 # There are three ways that a client can call the server
65 # 1. Blocking, with a response
66 (ok, response) = client_instance.call_with_response(service_method_name, service_request, timeout_ms=1000)
67 if (response):
68 print_service_response(response)
69 time.sleep(0.5)
70
71 # 2. Blocking with callback
72 ok = client_instance.call_with_callback(service_method_name, service_request, print_service_response, timeout_ms=1000)
73 time.sleep(0.5)
74
75 # 3. Asynchronous with callback
76 ok = client_instance.call_with_callback_async(service_method_name, service_request, print_service_response)
77 time.sleep(0.5)
78
79 del mirror_client
80
81 # finalize eCAL API
82 ecal_core.finalize()
83
84if __name__ == "__main__":
85 main()
1import sys
2import time
3
4import ecal.core.core as ecal_core
5import ecal.core.service as ecal_service
6
7def main():
8 # print eCAL version and date
9 print("eCAL {} ({})\n".format(ecal_core.getversion(), ecal_core.getdate()))
10
11 # initialize eCAL API
12 ecal_core.initialize("py_minimal_service_client")
13
14 # set process state
15 ecal_core.set_process_state(1, 1, "I feel good")
16
17 # create a client for the "DemoService" service
18 client = ecal_service.Client("DemoService")
19
20 # define the client response callback to catch server responses
21 def client_resp_callback(service_info, response):
22 if (service_info["call_state"] == "call_state_executed"):
23 print("'DemoService' method '{}' responded : '{}'".format(service_info["method_name"], response))
24 print()
25 else:
26 print("server {} response failed, error : '{}'".format(service_info["host_name"], service_info["error_msg"]))
27 print()
28
29 # and add it to the client
30 client.add_response_callback(client_resp_callback)
31
32 # idle and call service methods
33 i = 0
34 while(ecal_core.ok()):
35 i = i + 1
36 # call foo
37 request = bytes("hello foo {}".format(i), "ascii")
38 print("'DemoService' method 'foo' requested with : {}".format(request))
39 client.call_method("foo", request)
40 time.sleep(0.5)
41 # call ping
42 request = bytes("ping number {}".format(i), "ascii")
43 print("'DemoService' method 'ping' requested with : {}".format(request))
44 client.call_method("ping", request)
45 time.sleep(0.5)
46
47 # destroy client
48 client.destroy()
49
50 # finalize eCAL API
51 ecal_core.finalize()
52
53if __name__ == "__main__":
54 main()
├─ C++ │ └─mirror_client.cpp│ ├─ C │ └─mirror_client.c│ ├─ C# │ └─mirror_client.cs│ ├─ Python │ └─mirror_client.py│ └─ Python (legacy) └─mirror_client.py