Skip to content

Commit 36c2f59

Browse files
committed
Refs #23079. Add calculator IDL and example python code.
Signed-off-by: Miguel Company <miguelcompany@eprosima.com>
1 parent a8288c6 commit 36c2f59

2 files changed

Lines changed: 340 additions & 0 deletions

File tree

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
#!/usr/bin/env python3
2+
# # Copyright 2025 Proyectos y Sistemas de Mantenimiento SL (eProsima).
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
"""
16+
Script to test Fast DDS python bindings for RPC
17+
"""
18+
import os
19+
import argparse
20+
import threading
21+
import time
22+
23+
import fastdds
24+
import calculator
25+
26+
DESCRIPTION = """Calculator RPC example for Fast DDS python bindings"""
27+
USAGE = ('python3 CalculatorExample.py -p client|server [-d domainID -t server_threads]')
28+
29+
### Server implementation ###
30+
31+
class MyCalculatorImplementation(calculator.CalculatorServerImplementation):
32+
def __init__(self):
33+
super().__init__()
34+
35+
def operation_call_print(self, info, operation_name):
36+
print("Operation {op} called from client with id {id}".format(op=operation_name, id=info.get_client_id()))
37+
38+
def addition(self, info, value1, value2):
39+
self.operation_call_print(info, "addition")
40+
return value1 + value2
41+
42+
def subtraction(self, info, value1, value2):
43+
self.operation_call_print(info, "subtraction")
44+
return value1 - value2
45+
46+
def representation_limits(self, info):
47+
self.operation_call_print(info, "representation_limits")
48+
ret_val = calculator.BasicCalculator_representation_limits_Out()
49+
ret_val.min_value = -2147483648
50+
ret_val.max_value = 2147483647
51+
return ret_val
52+
53+
def fibonacci_seq(self, info, n_results, result_writer):
54+
self.operation_call_print(info, "fibonacci_seq")
55+
a = 1
56+
b = 1
57+
c = 0
58+
59+
while n_results > 0:
60+
n_results = n_results - 1
61+
62+
result_writer.write(a)
63+
c = a + b
64+
a = b
65+
b = c
66+
67+
def sum_all(self, info, value):
68+
self.operation_call_print(info, "sum_all")
69+
ret = 0
70+
has_value, n = value.read()
71+
while has_value:
72+
ret = ret + n
73+
has_value, n = value.read()
74+
return ret
75+
76+
def accumulator(self, info, value, result_writer):
77+
self.operation_call_print(info, "accumulator")
78+
ret = 0
79+
has_value, n = value.read()
80+
while has_value:
81+
ret = ret + n
82+
result_writer.write(ret)
83+
has_value, n = value.read()
84+
85+
### Server application ###
86+
87+
def run_server(server):
88+
server.run()
89+
90+
class Server:
91+
def __init__(self, domain, num_threads):
92+
# Create participant
93+
factory = fastdds.DomainParticipantFactory.get_instance()
94+
self.participant_qos = fastdds.DomainParticipantQos()
95+
factory.get_default_participant_qos(self.participant_qos)
96+
self.participant = factory.create_participant(domain, self.participant_qos)
97+
98+
# Create server
99+
self.implementation = MyCalculatorImplementation()
100+
self.server_qos = fastdds.ReplierQos()
101+
self.server = calculator.create_CalculatorServer(
102+
self.participant, "my_calculator", self.server_qos, num_threads, self.implementation)
103+
104+
def run(self):
105+
thr = threading.Thread(target=run_server, args=(self.server,))
106+
thr.start()
107+
print("Server is running. Press any key to stop it.")
108+
try:
109+
input()
110+
except:
111+
pass
112+
self.server.stop()
113+
thr.join()
114+
115+
### Client application ###
116+
117+
class Client:
118+
def __init__(self, domain):
119+
# Create participant
120+
factory = fastdds.DomainParticipantFactory.get_instance()
121+
self.participant_qos = fastdds.DomainParticipantQos()
122+
factory.get_default_participant_qos(self.participant_qos)
123+
self.participant = factory.create_participant(domain, self.participant_qos)
124+
125+
# Create client
126+
self.client_qos = fastdds.RequesterQos()
127+
self.client = calculator.create_CalculatorClient(
128+
self.participant, "my_calculator", self.client_qos)
129+
130+
def run(self):
131+
# TODO: wait for server to be ready
132+
time.sleep(2)
133+
134+
self.perform_addition()
135+
self.perform_subtraction()
136+
self.perform_representation_limits()
137+
self.perform_fibonacci_seq()
138+
self.perform_sum_all()
139+
self.perform_accumulator()
140+
141+
def perform_addition(self):
142+
try:
143+
# Perform basic addition
144+
print("Performing addition(1, 2)")
145+
result = self.client.addition(1, 2)
146+
print("Result: {}".format(result.get()))
147+
148+
# Perform addition with overflow
149+
print("Performing addition(2147483647, 1)")
150+
result = self.client.addition(2147483647, 1)
151+
print("Result: {}".format(result=result.get()))
152+
except Exception as e:
153+
print("Exception: {}".format(type(e).__name__))
154+
print("Exception message: {}".format(e))
155+
156+
def perform_subtraction(self):
157+
try:
158+
# Perform basic subtraction
159+
print("Performing subtraction(2, 1)")
160+
result = self.client.subtraction(2, 1)
161+
print("Result: {}".format(result.get()))
162+
163+
# Perform subtraction with underflow
164+
print("Performing subtraction(-2147483648, 1)")
165+
result = self.client.subtraction(-2147483648, 1)
166+
result.wait()
167+
print("Result: {}".format(result=result.get()))
168+
except Exception as e:
169+
print("Exception: {}".format(type(e).__name__))
170+
print("Exception message: {}".format(e))
171+
172+
def perform_representation_limits(self):
173+
try:
174+
# Perform representation limits
175+
print("Performing representation_limits()")
176+
result = self.client.representation_limits()
177+
data = result.get()
178+
print("Result: {min}, {max}".format(min=data.min_value, max=data.max_value))
179+
except Exception as e:
180+
print("Exception: {}".format(type(e).__name__))
181+
print("Exception message: {}".format(e))
182+
183+
def perform_fibonacci_seq(self):
184+
try:
185+
print("Performing fibonacci_seq(10)")
186+
result = self.client.fibonacci_seq(10)
187+
has_value, n = result.read()
188+
while has_value:
189+
print("Result: {}".format(n))
190+
has_value, n = result.read()
191+
except Exception as e:
192+
print("Exception: {}".format(type(e).__name__))
193+
print("Exception message: {}".format(e))
194+
195+
def perform_sum_all(self):
196+
try:
197+
print("Performing sum_all([1, 2, 3, 4, 5])")
198+
result, value = self.client.sum_all()
199+
value.write(1)
200+
value.write(2)
201+
value.write(3)
202+
value.write(4)
203+
value.write(5)
204+
value.finish()
205+
print("Result: {}".format(result.get()))
206+
except Exception as e:
207+
print("Exception: {}".format(type(e).__name__))
208+
print("Exception message: {}".format(e))
209+
210+
def perform_accumulator(self):
211+
try:
212+
print("Performing accumulator([1, 2, 3, 4, 5])")
213+
result, value = self.client.accumulator()
214+
value.write(1)
215+
value.write(2)
216+
value.write(3)
217+
value.write(4)
218+
value.write(5)
219+
value.finish()
220+
has_value, n = result.read()
221+
while has_value:
222+
print("Result: {}".format(n))
223+
has_value, n = result.read()
224+
except Exception as e:
225+
print("Exception: {}".format(type(e).__name__))
226+
print("Exception message: {}".format(e))
227+
228+
def parse_options():
229+
""""
230+
Parse arguments.
231+
232+
:return: Parsed arguments.
233+
"""
234+
parser = argparse.ArgumentParser(
235+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
236+
add_help=True,
237+
description=(DESCRIPTION),
238+
usage=(USAGE)
239+
)
240+
required_args = parser.add_argument_group('required arguments')
241+
required_args.add_argument(
242+
'-d',
243+
'--domain',
244+
type=int,
245+
required=False,
246+
help='DomainID.'
247+
)
248+
required_args.add_argument(
249+
'-p',
250+
'--parameter',
251+
type=str,
252+
required=True,
253+
help='Whether the application is run as client or server.'
254+
)
255+
required_args.add_argument(
256+
'-t',
257+
'--server_threads',
258+
type=int,
259+
required=False,
260+
help='Number of threads in the server pool. Only applies if the application is run as server.'
261+
)
262+
return parser.parse_args()
263+
264+
if __name__ == '__main__':
265+
# Parse arguments
266+
args = parse_options()
267+
if not args.domain:
268+
args.domain = 0
269+
if not args.server_threads:
270+
args.server_threads = 1
271+
272+
if args.parameter == 'client':
273+
print('Creating client.')
274+
client = Client(args.domain)
275+
client.run()
276+
elif args.parameter == 'server':
277+
print('Creating server.')
278+
server = Server(args.domain, args.server_threads)
279+
server.run()
280+
else:
281+
print('Error: Incorrect arguments.')
282+
print(USAGE)
283+
284+
exit()
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2025 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
module calculator_base
16+
{
17+
// This exception will be thrown when an operation result cannot be represented in a long
18+
exception OverflowException
19+
{
20+
};
21+
22+
@nested
23+
interface Adder
24+
{
25+
// Returns the result of value1 + value2
26+
long addition(in long value1, in long value2) raises(OverflowException);
27+
};
28+
29+
@nested
30+
interface Subtractor
31+
{
32+
// Returns the result of value1 - value2
33+
long subtraction(in long value1, in long value2) raises(OverflowException);
34+
};
35+
36+
interface BasicCalculator : Adder, Subtractor
37+
{
38+
// Returns the minimum and maximum representable values
39+
void representation_limits(out long min_value, out long max_value);
40+
};
41+
};
42+
43+
interface Calculator : calculator_base::BasicCalculator
44+
{
45+
// Returns a feed of results with the n_results first elements of the Fibonacci sequence
46+
// E.g. for an input of 5, returns a feed with {1, 1, 2, 3, 5}
47+
@feed long fibonacci_seq(in unsigned long n_results) raises (calculator_base::OverflowException);
48+
49+
// Waits for an input feed to finish and returns the sum of all the received values
50+
// E.g. for an input of {1, 2, 3, 4, 5} returns 15
51+
long sum_all(@feed in long value) raises (calculator_base::OverflowException);
52+
53+
// Returns a feed of results with the sum of all received values
54+
// E.g. for an input of {1, 2, 3, 4, 5}, returns a feed with {1, 3, 6, 10, 15}
55+
@feed long accumulator(@feed in long value) raises (calculator_base::OverflowException);
56+
};

0 commit comments

Comments
 (0)