diff --git a/ecal/core/CMakeLists.txt b/ecal/core/CMakeLists.txt index 699efdd52c..5a93f34118 100644 --- a/ecal/core/CMakeLists.txt +++ b/ecal/core/CMakeLists.txt @@ -605,9 +605,7 @@ set(ECAL_CORE_FEATURES foreach(CORE_FEATURE ${ECAL_CORE_FEATURES}) if(${CORE_FEATURE}) target_compile_definitions(${PROJECT_NAME} - PRIVATE ${CORE_FEATURE}) - target_compile_definitions(${PROJECT_NAME}_c - PRIVATE ${CORE_FEATURE}) + PUBLIC ${CORE_FEATURE}) endif() endforeach() diff --git a/ecal/core/src/pubsub/ecal_publisher.cpp b/ecal/core/src/pubsub/ecal_publisher.cpp index ef04c32cf5..5fba62ffd7 100644 --- a/ecal/core/src/pubsub/ecal_publisher.cpp +++ b/ecal/core/src/pubsub/ecal_publisher.cpp @@ -1,6 +1,6 @@ /* ========================= eCAL LICENSE ================================= * - * Copyright (C) 2016 - 2019 Continental Corporation + * Copyright (C) 2016 - 2024 Continental Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/lang/python/CMakeLists.txt b/lang/python/CMakeLists.txt index c2de24c73c..5bf59242d3 100644 --- a/lang/python/CMakeLists.txt +++ b/lang/python/CMakeLists.txt @@ -40,7 +40,7 @@ set(CMAKE_BUILD_WITH_INSTALL_RPATH "ON") add_subdirectory(core) add_dependencies(${PROJECT_NAME} _ecal_core_py) -add_subdirectory(nanobind_core) +add_subdirectory(nanobind_core/src) add_dependencies(${PROJECT_NAME} nanobind_core) if(HAS_HDF5) diff --git a/lang/python/nanobind_core/CMakeLists.txt b/lang/python/nanobind_core/CMakeLists.txt deleted file mode 100644 index 2cb06d3142..0000000000 --- a/lang/python/nanobind_core/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# Try to import all Python components potentially needed by nanobind -find_package(Python - REQUIRED COMPONENTS Interpreter Development.Module - OPTIONAL_COMPONENTS Development.SABIModule) - -# Import nanobind through CMake's find_package mechanism -find_package(nanobind CONFIG REQUIRED) - -# We are now ready to compile the actual extension module -nanobind_add_module( - # Name of the extension - nanobind_core - - # Target the stable ABI for Python 3.12+, which reduces - # the number of binary wheels that must be built. This - # does nothing on older Python versions - STABLE_ABI - - # Source code goes here - main.cpp -) - -# Install directive for scikit-build-core -install(TARGETS nanobind_core LIBRARY DESTINATION nanobind_core) - -if(WIN32) - set_property(TARGET nanobind_core PROPERTY FOLDER lang/python/core) -endif() \ No newline at end of file diff --git a/lang/python/nanobind_core/main.cpp b/lang/python/nanobind_core/main.cpp deleted file mode 100644 index 377ae791d1..0000000000 --- a/lang/python/nanobind_core/main.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include - -NB_MODULE(nanobind_core, m) { - m.def("hello", []() { return "Hello world!"; }); -} \ No newline at end of file diff --git a/lang/python/nanobind_core/samples/minimal_client.py b/lang/python/nanobind_core/samples/minimal_client.py new file mode 100644 index 0000000000..3fbcaee390 --- /dev/null +++ b/lang/python/nanobind_core/samples/minimal_client.py @@ -0,0 +1,69 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +from pickle import TRUE +import sys +import time + +import nanobind_core as ecal_core + + # define the client response callback to catch server responses +def client_resp_callback(service_info, response): + if (service_info["call_state"] == "call_state_executed"): + print("'DemoService' method '{}' responded : '{}'".format(service_info["method_name"], response)) + print() + else: + print("server {} response failed, error : '{}'".format(service_info["host_name"], service_info["error_msg"])) + print() + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create a client for the "DemoService" service + client = ecal_core.ServiceClient("DemoService") + + # and add it to the client + client.add_response_callback(client_resp_callback) + + # idle and call service methods + i = 0 + while(ecal_core.ok()): + i = i + 1 + # call foo + request = bytes("hello foo {}".format(i), "ascii") + print("'DemoService' method 'foo' requested with : {}".format(request)) + client.call("foo", "request", 1234) + time.sleep(0.5) + # call ping + request = bytes("ping number {}".format(i), "ascii") + print("'DemoService' method 'ping' requested with : {}".format(request)) + client.call("ping", "request", 1234) + time.sleep(0.5) + + # destroy client + client.destroy() + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() diff --git a/lang/python/nanobind_core/samples/minimal_rec.py b/lang/python/nanobind_core/samples/minimal_rec.py new file mode 100644 index 0000000000..84ebf7ea4b --- /dev/null +++ b/lang/python/nanobind_core/samples/minimal_rec.py @@ -0,0 +1,24 @@ +import sys + +import nanobind_core as ecal_core + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create subscriber + sub = ecal_core.Subscriber("Hello") + + # receive messages + while ecal_core.ok(): + msg = sub.receive(1234) + print("Received: {} ".format(msg)) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lang/python/nanobind_core/samples/minimal_rec_cb.py b/lang/python/nanobind_core/samples/minimal_rec_cb.py new file mode 100644 index 0000000000..a6c24e0647 --- /dev/null +++ b/lang/python/nanobind_core/samples/minimal_rec_cb.py @@ -0,0 +1,48 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +import sys +import time + +import nanobind_core as ecal_core + +# eCAL receive callback +def callback(topic_name, msg, time): + print("Received: {} ms {}".format(time, msg)) + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create subscriber and connect callback + sub = ecal_core.Subscriber("Hello") + sub.add_receive_callback(callback) + + # idle main thread + while ecal_core.ok(): + time.sleep(0.1) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() + diff --git a/lang/python/nanobind_core/samples/minimal_server.py b/lang/python/nanobind_core/samples/minimal_server.py new file mode 100644 index 0000000000..e6f90011ce --- /dev/null +++ b/lang/python/nanobind_core/samples/minimal_server.py @@ -0,0 +1,66 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +import sys +import time + +import nanobind_core as ecal_core + +# define the server method "foo" function +def foo_req_callback(method_name, req_type, resp_type, request): + print("'DemoService' method '{}' called with {}".format(method_name, request)) + #return True #, bytes("thank you for calling foo :-)", "ascii") + return 0, "pong" + +# define the server method "ping" function +def ping_req_callback(method_name, req_type, resp_type, request): + print("'DemoService' method '{}' called with {}".format(method_name, request)) + return 0, bytes("pong", "ascii") + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # initialize eCAL API + # ecal_core.initialize(sys.argv, "py_minimal_service_server") + + # set process state + # ecal_core.set_process_state(1, 1, "I feel good") + + # create a server for the "DemoService" service + server = ecal_core.ServiceServer("DemoService") + + # define the server methods and connect them to the callbacks + server.add_method_callback("foo", "string", "string", foo_req_callback) + server.add_method_callback("ping", "ping_type", "pong_type", ping_req_callback) + + # idle + while(ecal_core.ok()): + time.sleep(1.0) + + # destroy server + server.destroy() + + # finalize eCAL API + server.finalize() + +if __name__ == "__main__": + main() diff --git a/lang/python/nanobind_core/samples/minimal_snd.py b/lang/python/nanobind_core/samples/minimal_snd.py new file mode 100644 index 0000000000..79a9ae2453 --- /dev/null +++ b/lang/python/nanobind_core/samples/minimal_snd.py @@ -0,0 +1,30 @@ +import sys +import time + +import nanobind_core as ecal_core + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create publisher + pub = ecal_core.Publisher("Hello") + msg = "HELLO WORLD FROM PYTHON" + + # send messages + i = 0 + while ecal_core.ok(): + i = i + 1 + current_message = "{} {:6d}".format(msg, i) + print("Sending: {}".format(current_message)) + pub.send(current_message,1234) + time.sleep(0.5) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() diff --git a/lang/python/nanobind_core/samples/person_pb2.py b/lang/python/nanobind_core/samples/person_pb2.py new file mode 100644 index 0000000000..06a37d7836 --- /dev/null +++ b/lang/python/nanobind_core/samples/person_pb2.py @@ -0,0 +1,134 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: person.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +from google.protobuf import descriptor_pb2 +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +import animal_pb2 as animal__pb2 +import house_pb2 as house__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='person.proto', + package='pb.People', + syntax='proto3', + serialized_pb=_b('\n\x0cperson.proto\x12\tpb.People\x1a\x0c\x61nimal.proto\x1a\x0bhouse.proto\"\xbb\x01\n\x06Person\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12&\n\x05stype\x18\x03 \x01(\x0e\x32\x17.pb.People.Person.SType\x12\r\n\x05\x65mail\x18\x04 \x01(\t\x12\x1b\n\x03\x64og\x18\x05 \x01(\x0b\x32\x0e.pb.Animal.Dog\x12$\n\x05house\x18\x06 \x01(\x0b\x32\x15.pb.Environment.House\"\x1d\n\x05SType\x12\x08\n\x04MALE\x10\x00\x12\n\n\x06\x46\x45MALE\x10\x01\x62\x06proto3') + , + dependencies=[animal__pb2.DESCRIPTOR,house__pb2.DESCRIPTOR,]) +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + + + +_PERSON_STYPE = _descriptor.EnumDescriptor( + name='SType', + full_name='pb.People.Person.SType', + filename=None, + file=DESCRIPTOR, + values=[ + _descriptor.EnumValueDescriptor( + name='MALE', index=0, number=0, + options=None, + type=None), + _descriptor.EnumValueDescriptor( + name='FEMALE', index=1, number=1, + options=None, + type=None), + ], + containing_type=None, + options=None, + serialized_start=213, + serialized_end=242, +) +_sym_db.RegisterEnumDescriptor(_PERSON_STYPE) + + +_PERSON = _descriptor.Descriptor( + name='Person', + full_name='pb.People.Person', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='id', full_name='pb.People.Person.id', index=0, + number=1, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='name', full_name='pb.People.Person.name', index=1, + number=2, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='stype', full_name='pb.People.Person.stype', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='email', full_name='pb.People.Person.email', index=3, + number=4, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='dog', full_name='pb.People.Person.dog', index=4, + number=5, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + _descriptor.FieldDescriptor( + name='house', full_name='pb.People.Person.house', index=5, + number=6, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + options=None), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + _PERSON_STYPE, + ], + options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=55, + serialized_end=242, +) + +_PERSON.fields_by_name['stype'].enum_type = _PERSON_STYPE +_PERSON.fields_by_name['dog'].message_type = animal__pb2._DOG +_PERSON.fields_by_name['house'].message_type = house__pb2._HOUSE +_PERSON_STYPE.containing_type = _PERSON +DESCRIPTOR.message_types_by_name['Person'] = _PERSON + +Person = _reflection.GeneratedProtocolMessageType('Person', (_message.Message,), dict( + DESCRIPTOR = _PERSON, + __module__ = 'person_pb2' + # @@protoc_insertion_point(class_scope:pb.People.Person) + )) +_sym_db.RegisterMessage(Person) + + +# @@protoc_insertion_point(module_scope) diff --git a/lang/python/nanobind_core/samples/person_rec.py b/lang/python/nanobind_core/samples/person_rec.py new file mode 100644 index 0000000000..6bd3bc493c --- /dev/null +++ b/lang/python/nanobind_core/samples/person_rec.py @@ -0,0 +1,63 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +import os +import sys +import time + +import nanobind_core as ecal_core +from nb_subscriber import ProtoSubscriber + +sys.path.insert(1, os.path.join(sys.path[0], '../_protobuf')) +import person_pb2 + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # set process state + #ecal_core.set_process_state(1, 1, "I feel good") + + # create publisher + sub = ProtoSubscriber("person", person_pb2.Person) + + # receive messages + while ecal_core.ok(): + ret, person, time = sub.receive(500) + + # deserialize person from message buffer + if ret > 0: + # print person content + print("") + print("Received person ..") + print("person id : {}".format(person.id)) + print("person name : {}".format(person.name)) + print("person stype : {}".format(person.stype)) + print("person email : {}".format(person.email)) + print("dog.name : {}".format(person.dog.name)) + print("house.rooms : {}".format(person.house.rooms)) + + print("No reception") + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() diff --git a/lang/python/nanobind_core/samples/person_snd.py b/lang/python/nanobind_core/samples/person_snd.py new file mode 100644 index 0000000000..a41f9b85a3 --- /dev/null +++ b/lang/python/nanobind_core/samples/person_snd.py @@ -0,0 +1,69 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +import os +import sys +import time + +import nanobind_core as ecal_core +from nb_publisher import ProtoPublisher + +sys.path.insert(1, os.path.join(sys.path[0], '../_protobuf')) +import person_pb2 + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL AP + ecal_core.initialize() + + # set process state + #ecal_core.set_process_state(1, 1, "I feel good") + + # create publisher + pub = ProtoPublisher("person", person_pb2.Person) + print("ARIF CHECK 2") + # create person instance and set content + person = person_pb2.Person() + person.name = "Max" + person.stype = person_pb2.Person.MALE + person.email = "max@mail.net" + person.dog.name = "Brandy" + person.house.rooms = 4 + + + + # send messages + while ecal_core.ok(): + + # change person id + person.id = person.id + 1 + + # send person + print("Sending person {}".format(person.id)) + pub.send(person) + + # sleep 100 ms + time.sleep(0.1) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() diff --git a/lang/python/nanobind_core/src/CMakeLists.txt b/lang/python/nanobind_core/src/CMakeLists.txt new file mode 100644 index 0000000000..18f5591d9a --- /dev/null +++ b/lang/python/nanobind_core/src/CMakeLists.txt @@ -0,0 +1,62 @@ +# Try to import all Python components potentially needed by nanobind +find_package(Python + REQUIRED COMPONENTS Interpreter Development.Module + OPTIONAL_COMPONENTS Development.SABIModule) + +# Import nanobind through CMake's find_package mechanism +find_package(nanobind CONFIG REQUIRED) + +# We are now ready to compile the actual extension module +nanobind_add_module( + # Name of the extension + nanobind_core + + # Target the stable ABI for Python 3.12+, which reduces + # the number of binary wheels that must be built. This + # does nothing on older Python versions + STABLE_ABI + + # Source code goes here + modules/module_client.cpp + modules/module_client.h + modules/module_core.cpp + modules/module_core.h + modules/module_datatypeinfo.cpp + modules/module_datatypeinfo.h + modules/module_publisher.cpp + modules/module_publisher.h + modules/module_publisher_config.cpp + modules/module_publisher_config.h + modules/module_server.cpp + modules/module_server.h + modules/module_subscriber.cpp + modules/module_subscriber.h + modules/module_util.cpp + modules/module_util.h + + wrappers/wrapper_client.cpp + wrappers/wrapper_client.h + wrappers/wrapper_datatypeinfo.cpp + wrappers/wrapper_datatypeinfo.h + wrappers/wrapper_publisher.cpp + wrappers/wrapper_publisher.h + wrappers/wrapper_publisher_config.cpp + wrappers/wrapper_publisher_config.h + wrappers/wrapper_server.cpp + wrappers/wrapper_server.h + wrappers/wrapper_subscriber.cpp + wrappers/wrapper_subscriber.h + + nanobind_core.cpp +) + +target_include_directories(nanobind_core PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(nanobind_core PRIVATE eCAL::core) + +# Install directive for scikit-build-core +install(TARGETS nanobind_core LIBRARY DESTINATION nanobind_core) + +if(WIN32) + set_property(TARGET nanobind_core PROPERTY FOLDER lang/python/core) +endif() \ No newline at end of file diff --git a/lang/python/nanobind_core/src/modules/module_client.cpp b/lang/python/nanobind_core/src/modules/module_client.cpp new file mode 100644 index 0000000000..5d91475f92 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_client.cpp @@ -0,0 +1,57 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add ServiceClient class to nanobind module +**/ + + +#include +#include +#include + +void AddClientClassToModule(const nanobind::module_& module) +{ + /** + * @brief eCAL service client event callback type. + **/ + nanobind::enum_(module, "eCAL_Client_Event") + .value("client_event_none", eCAL_Client_Event::client_event_none) + .value("client_event_connected", eCAL_Client_Event::client_event_none) + .value("client_event_disconnected", eCAL_Client_Event::client_event_none) + .value("client_event_timeout", eCAL_Client_Event::client_event_none) + .export_values(); + + auto ServiceClient_cls = nanobind::class_(module, "ServiceClient") + .def(nanobind::init<>()) + .def(nanobind::init()) + // TODO Ariff : we now need the overloads here (with also Information, which also needs to be wrapped) + //.def("create", &eCAL::CNBSrvClient::Create) + .def("set_hostname", &eCAL::CNBSrvClient::SetHostName) + .def("destroy", &eCAL::CNBSrvClient::Destroy) + .def("call", nanobind::overload_cast(&eCAL::CNBSrvClient::Call)) + .def("call", nanobind::overload_cast(&eCAL::CNBSrvClient::Call)) + .def("call_async", &eCAL::CNBSrvClient::CallAsync) + .def("add_response_callback", &eCAL::CNBSrvClient::WrapAddRespCB) + .def("rem_response_callback", &eCAL::CNBSrvClient::RemResponseCallback) + .def("rem_event_callback", &eCAL::CNBSrvClient::RemEventCallback) + .def("add_event_callback", &eCAL::CNBSrvClient::WrapAddClientEventCB) + .def("is_connected", &eCAL::CNBSrvClient::IsConnected) + .def("get_service_name", &eCAL::CNBSrvClient::GetServiceName); +} diff --git a/lang/python/nanobind_core/src/modules/module_client.h b/lang/python/nanobind_core/src/modules/module_client.h new file mode 100644 index 0000000000..57a29b9865 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_client.h @@ -0,0 +1,48 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_client.h + * @brief Nanobind module for subsciber interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddClientClassToModule(const nanobind::module_& module); + + diff --git a/lang/python/nanobind_core/src/modules/module_core.cpp b/lang/python/nanobind_core/src/modules/module_core.cpp new file mode 100644 index 0000000000..38004de894 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_core.cpp @@ -0,0 +1,53 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add ecal_core functions to nanobind module +**/ + +#include +#include +#include + +void AddCoreFuncToModule(nanobind::module_& module) +{ + // Functions from ecal_core.h + module.def("get_version_string", []() { return eCAL::GetVersionString(); }); + module.def("get_version_date", []() { return eCAL::GetVersionDateString(); }); + module.def("set_unitname", [](const std::string& nb_unit_name) { return eCAL::SetUnitName(nb_unit_name.c_str()); }); + module.def("is_initialized", []() { return eCAL::IsInitialized(); }); + module.def("finalize", []() { return eCAL::Finalize(); }); + module.def("ok", []() { return eCAL::Ok(); }); + + module.def("get_version", []() + { + int nb_major; + int nb_minor; + int nb_patch; + int status = eCAL::GetVersion(&nb_major, &nb_minor, &nb_patch); + return std::make_tuple(status, nb_major, nb_minor, nb_patch); + }); + // m.def("initialize", [](int nb_argc_, char *nb_argv_, const char* nb_unit_name_, unsigned int nb_components_) + // { return eCAL::Initialize(nb_argc_, nb_argv_, nb_unit_name_, nb_components_); }); + module.def("initialize", [](std::vector nb_args_, std::string nb_unit_name_) + { return eCAL::Initialize(nb_args_, nb_unit_name_.c_str(), eCAL::Init::Default); }); + module.def("initialize", []() + { return eCAL::Initialize(); }); + +} diff --git a/lang/python/nanobind_core/src/modules/module_core.h b/lang/python/nanobind_core/src/modules/module_core.h new file mode 100644 index 0000000000..8db85ad8b2 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_core.h @@ -0,0 +1,46 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_core.h + * @brief Nanobind module for ecal_core functions +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddCoreFuncToModule(nanobind::module_& module); diff --git a/lang/python/nanobind_core/src/modules/module_datatypeinfo.cpp b/lang/python/nanobind_core/src/modules/module_datatypeinfo.cpp new file mode 100644 index 0000000000..3f47110b90 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_datatypeinfo.cpp @@ -0,0 +1,36 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add ServiceClient class to nanobind module +**/ + + +#include +#include + +void AddDataTypeInfoStructToModule(nanobind::module_& module) +{ + // Struct eCAL::SDataTypeInformation + nanobind::class_(module, "DataTypeInformation") + .def(nanobind::init<>()) + .def_rw("name", &eCAL::CNBDataTypeInformation::name) + .def_rw("encoding", &eCAL::CNBDataTypeInformation::encoding) + .def_rw("descriptor", &eCAL::CNBDataTypeInformation::descriptor); +} diff --git a/lang/python/nanobind_core/src/modules/module_datatypeinfo.h b/lang/python/nanobind_core/src/modules/module_datatypeinfo.h new file mode 100644 index 0000000000..5fbaeac902 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_datatypeinfo.h @@ -0,0 +1,46 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_datatypeinfo.h + * @brief Nanobind module for eCAL::SDataTypeInformation struct +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddDataTypeInfoStructToModule(nanobind::module_& module); diff --git a/lang/python/nanobind_core/src/modules/module_publisher.cpp b/lang/python/nanobind_core/src/modules/module_publisher.cpp new file mode 100644 index 0000000000..2a6f0fd0cf --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_publisher.cpp @@ -0,0 +1,54 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add publisher class to nanobind module +**/ + + +#include +#include + +void AddPublisherClassToModule(const nanobind::module_& module) +{ + // Class and Functions from ecal_publisher.h + auto Publisher_cls = nanobind::class_(module, "Publisher") + .def(nanobind::init<>()) + .def(nanobind::init()) + // TODO: we need the constructor with the eCAL::Publisher::Configuration, too + .def(nanobind::init()) + // .def(nanobind::self = nanobind::self) + .def("create", nanobind::overload_cast(&eCAL::CNBPublisher::Create)) + .def("create", nanobind::overload_cast(&eCAL::CNBPublisher::Create)) + .def("send", nanobind::overload_cast(&eCAL::CNBPublisher::Send)) + .def("send", nanobind::overload_cast(&eCAL::CNBPublisher::Send)) + .def("send", nanobind::overload_cast(&eCAL::CNBPublisher::Send)) + .def("destroy", &eCAL::CNBPublisher::Destroy) + .def("set_attribute", &eCAL::CNBPublisher::SetAttribute) + .def("clear_attribute", &eCAL::CNBPublisher::ClearAttribute) + .def("set_id", &eCAL::CNBPublisher::SetID) + .def("rem_event_callback", &eCAL::CNBPublisher::RemEventCallback) + .def("add_event_callback", &eCAL::CNBPublisher::AddEventCallback) + .def("is_created", &eCAL::CNBPublisher::IsCreated) + .def("is_subscribed", &eCAL::CNBPublisher::IsSubscribed) + .def("get_subscriber_count", &eCAL::CNBPublisher::GetSubscriberCount) + .def("get_topic_name", &eCAL::CNBPublisher::GetTopicName) + .def("get_datatype_information", &eCAL::CNBPublisher::GetDataTypeInformation) + .def("dump", &eCAL::CNBPublisher::Dump); +} diff --git a/lang/python/nanobind_core/src/modules/module_publisher.h b/lang/python/nanobind_core/src/modules/module_publisher.h new file mode 100644 index 0000000000..b35ab81417 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_publisher.h @@ -0,0 +1,48 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_subscriber.h + * @brief Nanobind module for subsciber interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddPublisherClassToModule(const nanobind::module_& module); + + diff --git a/lang/python/nanobind_core/src/modules/module_publisher_config.cpp b/lang/python/nanobind_core/src/modules/module_publisher_config.cpp new file mode 100644 index 0000000000..a52ac453b0 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_publisher_config.cpp @@ -0,0 +1,36 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add ServiceClient class to nanobind module +**/ + + +#include +#include + +void AddPublisherConfigStructToModule(nanobind::module_& module) +{ + // Struct eCAL::SDataTypeInformation + nanobind::class_(module, "PublisherConfiguration"); + // .def(nanobind::init<>()) + // .def_rw("name", &eCAL::CNBDataTypeInformation::name) + // .def_rw("encoding", &eCAL::CNBDataTypeInformation::encoding) + // .def_rw("descriptor", &eCAL::CNBDataTypeInformation::descriptor); +} diff --git a/lang/python/nanobind_core/src/modules/module_publisher_config.h b/lang/python/nanobind_core/src/modules/module_publisher_config.h new file mode 100644 index 0000000000..5fbaeac902 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_publisher_config.h @@ -0,0 +1,46 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_datatypeinfo.h + * @brief Nanobind module for eCAL::SDataTypeInformation struct +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddDataTypeInfoStructToModule(nanobind::module_& module); diff --git a/lang/python/nanobind_core/src/modules/module_server.cpp b/lang/python/nanobind_core/src/modules/module_server.cpp new file mode 100644 index 0000000000..7488ace06c --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_server.cpp @@ -0,0 +1,64 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add ServiceServer class to nanobind module +**/ + + +#include +#include + +void AddServerClassToModule(const nanobind::module_& module) +{ + /** + * @brief eCAL service server event callback type. + **/ + nanobind::enum_(module, "eCAL_Server_Event") + .value("server_event_none", eCAL_Server_Event::server_event_none) + .value("server_event_connected", eCAL_Server_Event::server_event_connected) + .value("server_event_disconnected", eCAL_Server_Event::server_event_disconnected) + .export_values(); + + // Struct eCAL::SServiceResponse + nanobind::class_(module, "ServiceResponse") + .def(nanobind::init<>()) + .def_rw("host_name", &eCAL::SServiceResponse::host_name) + .def_rw("service_name", &eCAL::SServiceResponse::service_name) + .def_rw("service_id", &eCAL::SServiceResponse::service_id) + .def_rw("method_name", &eCAL::SServiceResponse::method_name) + .def_rw("error_msg", &eCAL::SServiceResponse::error_msg) + .def_rw("ret_state", &eCAL::SServiceResponse::ret_state) + .def_rw("call_state", &eCAL::SServiceResponse::call_state) + .def_rw("response", &eCAL::SServiceResponse::response); + + // Class and Functions from ecal_server.h + auto ServiceServer_cls = nanobind::class_(module, "ServiceServer") + .def(nanobind::init<>()) + .def(nanobind::init()) + .def("create", &eCAL::CNBSrvServer::Create) + .def("add_description", &eCAL::CNBSrvServer::AddDescription) + .def("destroy", &eCAL::CNBSrvServer::Destroy) + .def("add_method_callback", &eCAL::CNBSrvServer::WrapAddMethodCB) + .def("rem_method_callback", &eCAL::CNBSrvServer::RemMethodCallback) + .def("rem_event_callback", &eCAL::CNBSrvServer::RemEventCallback) + .def("add_event_callback", &eCAL::CNBSrvServer::WrapAddSrvEventCB) + .def("is_connected", &eCAL::CNBSrvServer::IsConnected) + .def("get_service_name", &eCAL::CNBSrvServer::GetServiceName); +} diff --git a/lang/python/nanobind_core/src/modules/module_server.h b/lang/python/nanobind_core/src/modules/module_server.h new file mode 100644 index 0000000000..7e13e861cf --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_server.h @@ -0,0 +1,47 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_server.h + * @brief Nanobind module for subsciber interface +**/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddServerClassToModule(const nanobind::module_& module); + + diff --git a/lang/python/nanobind_core/src/modules/module_subscriber.cpp b/lang/python/nanobind_core/src/modules/module_subscriber.cpp new file mode 100644 index 0000000000..84d7ebdfee --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_subscriber.cpp @@ -0,0 +1,51 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add subscriber class to nanobind module +**/ + + +#include +#include + +void AddSubscriberClassToModule(const nanobind::module_& module) +{ + auto Subscriber_cls = nanobind::class_(module, "Subscriber") + .def(nanobind::init<>()) + .def(nanobind::init()) + .def(nanobind::init()) + .def("receive", &eCAL::CNBSubscriber::Receive) + .def("create", nanobind::overload_cast(&eCAL::CNBSubscriber::Create)) + .def("create", nanobind::overload_cast(&eCAL::CNBSubscriber::Create)) + .def("destroy", &eCAL::CNBSubscriber::Destroy) + .def("set_attribute", &eCAL::CNBSubscriber::SetAttribute) + .def("clear_attribute", &eCAL::CNBSubscriber::ClearAttribute) + .def("set_id", &eCAL::CNBSubscriber::SetID) + .def("receive_buffer", &eCAL::CNBSubscriber::ReceiveBuffer) + .def("add_receive_callback", &eCAL::CNBSubscriber::WrapAddRecCB) + .def("rem_receive_callback", &eCAL::CNBSubscriber::RemReceiveCallback) + .def("rem_event_callback", &eCAL::CNBSubscriber::RemEventCallback) + .def("add_event_callback", &eCAL::CNBSubscriber::AddEventCallback) + .def("is_created", &eCAL::CNBSubscriber::IsCreated) + .def("get_publisher_count", &eCAL::CNBSubscriber::GetPublisherCount) + .def("get_topic_name", &eCAL::CNBSubscriber::GetTopicName) + .def("get_datatype_information", &eCAL::CNBSubscriber::GetDataTypeInformation) + .def("dump", &eCAL::CNBSubscriber::Dump); +} diff --git a/lang/python/nanobind_core/src/modules/module_subscriber.h b/lang/python/nanobind_core/src/modules/module_subscriber.h new file mode 100644 index 0000000000..6da3c53b59 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_subscriber.h @@ -0,0 +1,48 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_subscriber.h + * @brief Nanobind module for subsciber interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddSubscriberClassToModule(const nanobind::module_& module); + + diff --git a/lang/python/nanobind_core/src/modules/module_util.cpp b/lang/python/nanobind_core/src/modules/module_util.cpp new file mode 100644 index 0000000000..c1a1e25144 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_util.cpp @@ -0,0 +1,76 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Add ecal_util functions to nanobind module +**/ + +#include +#include + +void AddUtilFuncToModule(nanobind::module_& module) +{ + // Functions from ecal_util.h + module.def("enable_loopback", [](bool nb_state_) { return eCAL::Util::EnableLoopback(nb_state_); }); + module.def("pub_share_type", [](bool nb_state_) { return eCAL::Util::PubShareType(nb_state_); }); + module.def("pub_share_description", [](bool nb_state_) { return eCAL::Util::PubShareDescription(nb_state_); }); + +#if ECAL_CORE_MONITORING + module.def("shutdown_core", []() { return eCAL::Util::ShutdownCore(); }); + module.def("shutdown_processes", []() { return eCAL::Util::ShutdownProcesses(); }); + module.def("shutdown_process", [](const std::string& nb_process_name_) { return eCAL::Util::ShutdownProcess(nb_process_name_); }); + module.def("shutdown_process", [](const int nb_process_id_) { return eCAL::Util::ShutdownProcess(nb_process_id_); }); +#endif // ECAL_CORE_MONITORING + + module.def("get_user_settings_path", []() { return eCAL::Util::GeteCALUserSettingsPath(); }); + module.def("get_log_path", []() { return eCAL::Util::GeteCALLogPath(); }); + module.def("get_config_path", []() { return eCAL::Util::GeteCALConfigPath(); }); + module.def("get_active_ini_file", []() { return eCAL::Util::GeteCALActiveIniFile(); }); + + // TODO Ariff: function changed + //module.def("get_topics", [](std::unordered_map& nb_topic_info_map_) + // { return eCAL::Util::GetTopics(nb_topic_info_map_); }); + + // TODO Ariff: function changed + //module.def("get_topic_names", [](std::vector& nb_topic_names_) + // { return eCAL::Util::GetTopicNames(nb_topic_names_); }); + module.def("get_topic_datatype_info", [](const std::string& nb_topic_name_) + { + eCAL::SDataTypeInformation nb_topic_info_; + auto success = eCAL::Util::GetTopicDataTypeInformation(nb_topic_name_, nb_topic_info_); + auto return_value = nanobind::make_tuple(success, nb_topic_info_); + return return_value; + }); + + // m.def("getservices", [](std::map, eCAL::SServiceMethodInformation>& nb_service_info_map_) + // { return eCAL::Util::GetServices(nb_service_info_map_); }); + + // TODO Ariff: function changed + //module.def("get_service_names", [](std::vector>& nb_service_method_names_) + // { return eCAL::Util::GetServiceNames(nb_service_method_names_); }); + module.def("get_service_type_names", [](const std::string& nb_service_name_, const std::string& nb_method_name_, std::string& nb_req_type_, std::string& nb_resp_type_) + { return eCAL::Util::GetServiceTypeNames(nb_service_name_, nb_method_name_, nb_req_type_, nb_resp_type_); }); + module.def("get_service_description", [](const std::string& nb_service_name_, const std::string& nb_method_name_, std::string& nb_req_desc_, std::string& nb_resp_desc_) + { return eCAL::Util::GetServiceDescription(nb_service_name_, nb_method_name_, nb_req_desc_, nb_resp_desc_); }); + + module.def("split_combined_topic_type", [](const std::string& nb_combined_topic_type_) + { return eCAL::Util::SplitCombinedTopicType(nb_combined_topic_type_); }); + module.def("combined_topic_encoding_and_type", [](const std::string& nb_topic_encoding_, const std::string& nb_topic_type_) + { return eCAL::Util::CombinedTopicEncodingAndType(nb_topic_encoding_, nb_topic_type_); }); +} diff --git a/lang/python/nanobind_core/src/modules/module_util.h b/lang/python/nanobind_core/src/modules/module_util.h new file mode 100644 index 0000000000..f9e77e4278 --- /dev/null +++ b/lang/python/nanobind_core/src/modules/module_util.h @@ -0,0 +1,48 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file module_util.h + * @brief Nanobind module for ecal_util functions +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @brief Function to Add Nanobind module + * + * @param module The nanobind module variable +**/ +void AddUtilFuncToModule(nanobind::module_& module); + + diff --git a/lang/python/nanobind_core/src/nanobind_core.cpp b/lang/python/nanobind_core/src/nanobind_core.cpp new file mode 100644 index 0000000000..ef81bd9ca0 --- /dev/null +++ b/lang/python/nanobind_core/src/nanobind_core.cpp @@ -0,0 +1,57 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief Main Nanobind module which Adds all other needed classes and functions +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +NB_MODULE(nanobind_core, m) { + + AddDataTypeInfoStructToModule(m); + AddSubscriberClassToModule(m); + AddPublisherClassToModule(m); + AddClientClassToModule(m); + AddServerClassToModule(m); + + AddCoreFuncToModule(m); + AddUtilFuncToModule(m); +} diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_client.cpp b/lang/python/nanobind_core/src/wrappers/wrapper_client.cpp new file mode 100644 index 0000000000..5e7ae8c694 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_client.cpp @@ -0,0 +1,94 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief common data service client based on eCAL, adapted for Nanobind +**/ + +#include +#include + +#include +#include +#include +#include +#include + +namespace eCAL +{ + CNBSrvClient::CNBSrvClient() : CServiceClient() { } + + CNBSrvClient::CNBSrvClient(const std::string& service_name) : CServiceClient(service_name) { } + + bool CNBSrvClient::WrapAddRespCB(nanobind::callable callback_) + { + assert(IsConnected()); + { + std::lock_guard callback_lock(m_python_resp_callback_mutex); + m_python_resp_callback = callback_; + } + auto callback = std::bind(&CNBSrvClient::ResponseCallback, this, std::placeholders::_1); + return(CServiceClient::AddResponseCallback(callback)); + } + + bool CNBSrvClient::WrapAddClientEventCB(eCAL_Client_Event type, nanobind::callable callback_) + { + assert(IsConnected()); + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + m_python_event_callback = callback_; + } + auto callback = std::bind(&CNBSrvClient::AddCltEventCB, this, std::placeholders::_1, std::placeholders::_2); + return(CNBSrvClient::AddEventCallback(type, callback)); + } + + void CNBSrvClient::ResponseCallback(const struct SServiceResponse& data_) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_resp_callback_mutex); + fn_callback = m_python_resp_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + fn_callback(data_.service_name, data_.response); + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + void CNBSrvClient::AddCltEventCB(const char* client_name_, const struct SClientEventCallbackData* data_) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + fn_callback = m_python_event_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + fn_callback(client_name_, data_->type, nanobind::int_(data_->time), data_->attr.hname); + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_client.h b/lang/python/nanobind_core/src/wrappers/wrapper_client.h new file mode 100644 index 0000000000..7bd567c38f --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_client.h @@ -0,0 +1,96 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file wrapper_client.h + * @brief Nanobind wrapper client interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace eCAL +{ + class CNBSrvClient : public CServiceClient + { + public: + /** + * @brief Constructor. + **/ + CNBSrvClient(); + + /** + * @brief Constructor. + * + * @param service_name Unique service name. + **/ + CNBSrvClient(const std::string& service_name); + + /** + * @brief Wrapper for Add callback function for incoming responses. + * + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddRespCB(nanobind::callable callback_); + + /** + * @brief Wrapper for Add callback function for service client events. + * + * @param type The event type to react on. + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddClientEventCB(eCAL_Client_Event type, nanobind::callable callback_); + + private: + /** + * @brief Private function to receive python parameters for incoming response. + * + * @param data_ eCAL Service response callback struct. + **/ + void ResponseCallback(const struct SServiceResponse& data_); + + /** + * @brief Private function to receive python parameters for subscriber events. + * + * @param client_name_ The client name + * @param data_ eCAL client event callback struct. + **/ + void AddCltEventCB(const char* client_name_, const struct SClientEventCallbackData* data_); + + // class members + nanobind::callable m_python_event_callback; + std::mutex m_python_event_callback_mutex; + + nanobind::callable m_python_resp_callback; + std::mutex m_python_resp_callback_mutex; + }; +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_datatypeinfo.cpp b/lang/python/nanobind_core/src/wrappers/wrapper_datatypeinfo.cpp new file mode 100644 index 0000000000..f38f7331d6 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_datatypeinfo.cpp @@ -0,0 +1,41 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief common datatype info based on eCAL, adapted for Nanobind +**/ + +#include +#include +#include +#include +#include + +#include + +namespace eCAL +{ + SDataTypeInformation convert(const CNBDataTypeInformation& nb_info) + { + SDataTypeInformation info; + info.name = nb_info.name; + info.encoding = nb_info.encoding; + info.descriptor = std::string(nb_info.descriptor.c_str(), nb_info.descriptor.size()); + } +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_datatypeinfo.h b/lang/python/nanobind_core/src/wrappers/wrapper_datatypeinfo.h new file mode 100644 index 0000000000..5431e5df18 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_datatypeinfo.h @@ -0,0 +1,53 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file wrapper_datatypeinfo.h + * @brief Nanobind wrapper SDataTypeInformation struct +**/ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace eCAL +{ + class CNBDataTypeInformation + { + public: + std::string name; + std::string encoding; + nanobind::bytes descriptor; + }; + + /** + * @brief Convert function for SDataTypeInformation + * + * @param nb_info CNBDataTypeInformation struct + * + * @return SDataTypeInformation struct after convertion + **/ + SDataTypeInformation convert(const CNBDataTypeInformation& nb_info); +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_publisher.cpp b/lang/python/nanobind_core/src/wrappers/wrapper_publisher.cpp new file mode 100644 index 0000000000..09971e28bd --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_publisher.cpp @@ -0,0 +1,70 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief common data publisher based on eCAL, adapted for Nanobind +**/ + +#include +#include + +#include +#include +#include +#include +#include + +namespace eCAL +{ + CNBPublisher::CNBPublisher() : CPublisher() { } + + CNBPublisher::CNBPublisher(const std::string& topic_name) : CPublisher(topic_name) { } + + CNBPublisher::CNBPublisher(const std::string& topic_name, const CNBDataTypeInformation& datainfo) : CPublisher(topic_name, convert(datainfo)) { } + + bool CNBPublisher::WrapAddPubEventCB(eCAL_Publisher_Event event, nanobind::callable callback_) + { + assert(IsCreated()); + RemEventCallback(event); + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + m_python_event_callback = callback_; + } + auto callback = std::bind(&CNBPublisher::AddPubEventCB, this, std::placeholders::_1, std::placeholders::_2); + return(CPublisher::AddEventCallback(event, callback)); + } + + void CNBPublisher::AddPubEventCB(const char* event_name_, const struct eCAL::SPubEventCallbackData* data_) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + fn_callback = m_python_event_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + fn_callback(event_name_, data_->type, nanobind::int_(data_->time), data_->tid); + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_publisher.h b/lang/python/nanobind_core/src/wrappers/wrapper_publisher.h new file mode 100644 index 0000000000..3fa969fc0d --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_publisher.h @@ -0,0 +1,87 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file wrapper_publisher.h + * @brief Nanobind wrapper publisher interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace eCAL +{ + class CNBPublisher : public CPublisher + { + public: + /** + * @brief Constructor. + **/ + CNBPublisher(); + + /** + * @brief Constructor. + * + * @param topic_name Unique topic name. + **/ + CNBPublisher(const std::string& topic_name); + + /** + * @brief Constructor. + * + * @param topic_name Unique topic name. + * @param datainfo Topic information (encoding, type, descriptor) + **/ + CNBPublisher(const std::string& topic_name, const CNBDataTypeInformation& datainfo); + + /** + * @brief Wrapper for Add callback function for publisher events. + * + * @param event The event type to react on. + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddPubEventCB(eCAL_Publisher_Event event, nanobind::callable callback_); + + private: + /** + * @brief Private function to receive python parameters for publisher events. + * + * @param event_name_ The event type to react on. + * @param data_ eCAL publisher event callback struct. + **/ + void AddPubEventCB(const char* event_name_, const struct eCAL::SPubEventCallbackData* data_); + + // class members + nanobind::callable m_python_event_callback; + std::mutex m_python_event_callback_mutex; + + }; +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_publisher_config.cpp b/lang/python/nanobind_core/src/wrappers/wrapper_publisher_config.cpp new file mode 100644 index 0000000000..b83f17ec93 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_publisher_config.cpp @@ -0,0 +1,33 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief publisher configuration, adapted for Nanobind +**/ + +#include + +namespace eCAL +{ + // TODO @Ariff + Publisher::Configuration convert(const CNBPublisherConfigStruct& nb_config) + { + return Publisher::Configuration{}; + } +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_publisher_config.h b/lang/python/nanobind_core/src/wrappers/wrapper_publisher_config.h new file mode 100644 index 0000000000..75a56d534b --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_publisher_config.h @@ -0,0 +1,50 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file wrapper_datatypeinfo.h + * @brief Nanobind wrapper SDataTypeInformation struct +**/ + +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace eCAL +{ + // TODO @Ariff + class CNBPublisherConfigStruct + { + }; + + /** + * @brief Convert function for SDataTypeInformation + * + * @param nb_info CNBDataTypeInformation struct + * + * @return SDataTypeInformation struct after convertion + **/ + Publisher::Configuration convert(const CNBPublisherConfigStruct& nb_config); +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_server.cpp b/lang/python/nanobind_core/src/wrappers/wrapper_server.cpp new file mode 100644 index 0000000000..1d5b985535 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_server.cpp @@ -0,0 +1,100 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief common data service client based on eCAL, adapted for Nanobind +**/ + +#include +#include + +#include +#include +#include +#include +#include + +namespace eCAL +{ + CNBSrvServer::CNBSrvServer() : CServiceServer() { } + + CNBSrvServer::CNBSrvServer(const std::string& service_name) : CServiceServer(service_name) { } + + bool CNBSrvServer::WrapAddMethodCB(const std::string& nb_method, const std::string& nb_req_type, const std::string& nb_resp_type, nanobind::callable callback_) + { + assert(IsConnected()); + { + std::lock_guard callback_lock(m_python_method_callback_mutex); + m_python_method_callback = callback_; + } + auto Servercallback = std::bind(&CNBSrvServer::MethodCallback, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5); + return(CNBSrvServer::AddMethodCallback(nb_method, nb_req_type, nb_resp_type, Servercallback)); + } + + bool CNBSrvServer::WrapAddSrvEventCB(eCAL_Server_Event type, nanobind::callable callback_) + { + assert(IsConnected()); + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + m_python_event_callback = callback_; + } + auto callback = std::bind(&CNBSrvServer::AddSrvEventCB, this, std::placeholders::_1, std::placeholders::_2); + return(CNBSrvServer::AddEventCallback(type, callback)); + } + + int CNBSrvServer::MethodCallback(const std::string& method_, const std::string& req_type_, const std::string& resp_type_, const std::string& request, std::string& response) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_method_callback_mutex); + fn_callback = m_python_method_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + auto result = fn_callback(method_, req_type_, resp_type_, request); + // do some check if object holds a tuple if (!result.is_type) + nanobind::tuple result_tuple = nanobind::cast(result); + response = nanobind::cast(result[1]); + int nb_int = nanobind::cast(result[0]); + return nb_int; + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + + void CNBSrvServer::AddSrvEventCB(const char* client_name_, const struct SServerEventCallbackData* data_) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + fn_callback = m_python_event_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + fn_callback(client_name_, data_->type, nanobind::int_(data_->time)); + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + +} diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_server.h b/lang/python/nanobind_core/src/wrappers/wrapper_server.h new file mode 100644 index 0000000000..9f8117abe1 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_server.h @@ -0,0 +1,106 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file wrapper_server.h + * @brief Nanobind wrapper server interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace eCAL +{ + class CNBSrvServer : public CServiceServer + { + public: + /** + * @brief Constructor. + **/ + CNBSrvServer(); + + /** + * @brief Constructor. + * + * @param service_name Unique service name. + **/ + CNBSrvServer(const std::string& service_name); + + /** + * @brief Wrapper for Add callback function for service client events. + * + * @param nb_method Service method name + * @param nb_req_type Service method request type. + * @param nb_resp_type Service method response type. + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddMethodCB(const std::string& nb_method, const std::string& nb_req_type, const std::string& nb_resp_type, nanobind::callable callback_); + + /** + * @brief Wrapper for Add callback function for service client events. + * + * @param type The event type to react on. + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddSrvEventCB(eCAL_Server_Event type, nanobind::callable callback_); + + private: + /** + * @brief Private function to receive python parameters for method. + * + * @param nb_method Service method name + * @param nb_req_type Service method request type. + * @param nb_resp_type Service method response type. + * @param request Server request + * @param response Server response + * @param callback_ The callback function to add. + * + * @return Result + **/ + int MethodCallback(const std::string& method_, const std::string& req_type_, const std::string& resp_type_, const std::string& request, std::string& response); + + /** + * @brief Private function to receive python parameters for server events. + * + * @param client_name_ The client name + * @param data_ eCAL client event callback struct. + **/ + void AddSrvEventCB(const char* client_name_, const struct SServerEventCallbackData* data_); + + // class members + nanobind::callable m_python_event_callback; + std::mutex m_python_event_callback_mutex; + + nanobind::callable m_python_method_callback; + std::mutex m_python_method_callback_mutex; + }; +} diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_subscriber.cpp b/lang/python/nanobind_core/src/wrappers/wrapper_subscriber.cpp new file mode 100644 index 0000000000..c0cdd2151c --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_subscriber.cpp @@ -0,0 +1,107 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @brief common data subscriber based on eCAL, adapted for Nanobind +**/ + +#include +#include + +#include +#include +#include +#include + + +namespace eCAL +{ + CNBSubscriber::CNBSubscriber() : CSubscriber() { } + + CNBSubscriber::CNBSubscriber(const std::string& topic_name) : CSubscriber(topic_name) { } + + CNBSubscriber::CNBSubscriber(const std::string& topic_name, const CNBDataTypeInformation& datainfo) : CSubscriber(topic_name, convert(datainfo)) { } + + std::string CNBSubscriber::Receive(int nb_timeout) + { + std::string Rec_Data = ""; + auto success = eCAL::CSubscriber::ReceiveBuffer(Rec_Data, nullptr, nb_timeout); + return(Rec_Data); + } + + bool CNBSubscriber::WrapAddRecCB(nanobind::callable callback_) + { + assert(IsCreated()); + RemReceiveCallback(); + + { + std::lock_guard callback_lock(m_python_rec_callback_mutex); + m_python_rec_callback = callback_; + } + auto callback = std::bind(&CNBSubscriber::ReceiveCallback, this, std::placeholders::_1, std::placeholders::_2); + return(CSubscriber::AddReceiveCallback(callback)); + } + + bool CNBSubscriber::WrapAddSubEventCB(eCAL_Subscriber_Event event, nanobind::callable callback_) + { + assert(IsCreated()); + RemEventCallback(event); + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + m_python_event_callback = callback_; + } + auto callback = std::bind(&CNBSubscriber::AddSubEventCB, this, std::placeholders::_1, std::placeholders::_2); + return(CSubscriber::AddEventCallback(event, callback)); + } + + void CNBSubscriber::ReceiveCallback(const char* topic_name_, const struct eCAL::SReceiveCallbackData* data_) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_rec_callback_mutex); + fn_callback = m_python_rec_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + fn_callback(nanobind::str(topic_name_), nanobind::bytes((const char*)data_->buf, data_->size), nanobind::int_(data_->time)); + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + + void CNBSubscriber::AddSubEventCB(const char* event_name_, const struct eCAL::SSubEventCallbackData* data_) + { + nanobind::callable fn_callback; + { + std::lock_guard callback_lock(m_python_event_callback_mutex); + fn_callback = m_python_event_callback; + } + + try { + nanobind::gil_scoped_acquire g2; + fn_callback(event_name_, data_->type, nanobind::int_(data_->time), data_->tid); + } + catch (const nanobind::python_error& e) { + std::cout << e.what(); + } + } + +} \ No newline at end of file diff --git a/lang/python/nanobind_core/src/wrappers/wrapper_subscriber.h b/lang/python/nanobind_core/src/wrappers/wrapper_subscriber.h new file mode 100644 index 0000000000..a89d6ed4f7 --- /dev/null +++ b/lang/python/nanobind_core/src/wrappers/wrapper_subscriber.h @@ -0,0 +1,114 @@ +/* ========================= eCAL LICENSE ================================= + * + * Copyright (C) 2016 - 2024 Continental Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ========================= eCAL LICENSE ================================= +*/ + +/** + * @file wrapper_subscriber.h + * @brief Nanobind wrapper subscriber interface +**/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace eCAL +{ + class CNBSubscriber : public CSubscriber + { + public: + /** + * @brief Constructor. + **/ + CNBSubscriber(); + + /** + * @brief Constructor. + * + * @param topic_name Unique topic name. + **/ + CNBSubscriber(const std::string& topic_name); + /** + * @brief Constructor. + * + * @param topic_name Unique topic name. + * @param datainfo Topic information (encoding, type, descriptor) + **/ + CNBSubscriber(const std::string& topic_name, const CNBDataTypeInformation& datainfo); + + /** + * @brief Receive a message from the publisher (able to process zero length buffer). + * + * @param nb_timeout Maximum time before receive operation returns (in milliseconds, -1 means infinite). + * + * @return Standard string for containing message content. + **/ + std::string Receive(int nb_timeout); + + /** + * @brief Wrapper for Add callback function for incoming receives. + * + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddRecCB(nanobind::callable callback_); + + /** + * @brief Wrapper for Add callback function for subscriber events. + * + * @param event The event type to react on. + * @param callback_ The callback function to add. + * + * @return True if succeeded, false if not. + **/ + bool WrapAddSubEventCB(eCAL_Subscriber_Event event, nanobind::callable callback_); + + private: + /** + * @brief Private function to receive python parameters for incoming receives. + * + * @param topic_name_ The topic name of the received message. + * @param data_ eCAL subscriber receive callback struct. + **/ + void ReceiveCallback(const char* topic_name_, const struct eCAL::SReceiveCallbackData* data_); + + /** + * @brief Private function to receive python parameters for subscriber events. + * + * @param event_name_ The event type to react on. + * @param data_ eCAL subscriber event callback struct. + **/ + void AddSubEventCB(const char* event_name_, const struct eCAL::SSubEventCallbackData* data_); + + // class members + nanobind::callable m_python_event_callback; + std::mutex m_python_event_callback_mutex; + + nanobind::callable m_python_rec_callback; + std::mutex m_python_rec_callback_mutex; + }; +} \ No newline at end of file diff --git a/lang/python/nanobind_core/test_nb.py b/lang/python/nanobind_core/test_nb.py new file mode 100644 index 0000000000..b381566b74 --- /dev/null +++ b/lang/python/nanobind_core/test_nb.py @@ -0,0 +1,106 @@ +import re +import sys +import nanobind_core as t +# import pytest +# from common import skip_on_pypy, collect + +import unittest + +class NBUnitTest(unittest.TestCase): + + def test01_noparam_functions(self): + # print(sys.argv) + print('Initialise:',t.initialize()) + # Functions without any parameters + print('===============') + print('Lamda Functions') + print('===============') + print('Version String:',t.get_version_string()) + print('Version Date:',t.get_version_date()) + print('Check OK:',t.ok()) + print('Set Unitname:',t.set_unitname("Unit1")) + print('Is Initialised:',t.is_initialised()) + # print('Finalize:',t.finalize(123)) + print('User Settings Path:',t.get_user_settings_path()) + print('Log Path:',t.get_log_path()) + print('Config Path:',t.get_config_path()) + print('Active ini File:',t.get_active_ini_file()) + # assert t.shutdown_core() is None + # assert t.shutdown_processes() is None + # test suite for subscriber class + subscriber_obj = t.Subscriber("foo") + print('=========================') + print('Subsriber Class Functions') + print('=========================') + print('Create Successful:',subscriber_obj.create("trz")) + print('Subscriber is Created:',subscriber_obj.is_created()) + print('Set Attribute:',subscriber_obj.set_attribute("Attribute1","Attrib_Value")) + print('Clear Attribute:',subscriber_obj.clear_attribute("Attribute1")) + print('Clear Attribute Retry:',subscriber_obj.clear_attribute("Attribu")) +# print('Set ID:',subscriber_obj.set_id(1234)) + print('Topic Name:',subscriber_obj.get_topic_name()) + print('Publisher Count:',subscriber_obj.get_publisher_count()) + print('Datatype Info:',subscriber_obj.get_datatype_information()) + print('Destroy Successful:',subscriber_obj.destroy()) + print('Subscriber is Created:',subscriber_obj.is_created()) + # test suite for publisher class + print('=========================') + print('Publisher Class Functions') + print('=========================') + publisher_obj = t.Publisher("foo_pub") + print('Create Successful:',publisher_obj.create("try2")) + print('Publisher is Created:',publisher_obj.is_created()) + print('Is Subsribed:',publisher_obj.is_subscribed()) + print('Set Attribute:',publisher_obj.set_attribute("Attribute1","Attrib_Value")) + print('Clear Attribute:',publisher_obj.clear_attribute("Attribute1")) + print('Clear Attribute Retry:',publisher_obj.clear_attribute("Attribu")) +# print('Set ID:',publisher_obj.set_id(1234)) + print('Share Type:',publisher_obj.share_type(True)) + print('Topic Name:',publisher_obj.get_topic_name()) + print('Subscriber Count:',publisher_obj.get_subscriber_count()) + print('Datatype Info:',publisher_obj.get_datatype_information()) + print('Destroy Successful:',publisher_obj.destroy()) + print('Subscriber is Created:',publisher_obj.is_created()) + print('Dump Successful:',publisher_obj.dump("ABC")) + # test suite for Client class + print('======================') + print('Client Class Functions') + print('======================') + client_obj = t.ServiceClient("client1") + print('Create Successful:',client_obj.create("ClientTry")) + print('Set Hostname:',client_obj.set_hostname("ClientHost1")) + print('Service Name:',client_obj.get_service_name()) + print('Is Connected:',client_obj.is_connected()) + print('Destroy Successful:',client_obj.destroy()) + # test suite for Server class + print('======================') + print('Server Class Functions') + print('======================') + server_obj = t.ServiceServer("server1") + print('Create Successful:',server_obj.create("ServerTry")) + print('Service Name:',server_obj.get_service_name()) + print('Is Connected:',server_obj.is_connected()) + print('Destroy Successful:',server_obj.destroy()) + # test suite for ClientServer interaction + print('=========================') + print('Client-Server Interaction') + print('=========================') + print('Call Server:',client_obj.call("Method1","Request1",10000)) + # print('Call Method Response:',server_obj.add_method_callback("Method1","Request1",10000)) + + + +if __name__ == '__main__': + unittest.main() + +# def test02_bool_functions(): +# assert t.enable_loopback(True) is None +# assert t.pub_share_type(True) is None +# assert t.pub_share_description(True) is None +# assert t.enable_loopback(False) is None +# assert t.pub_share_type(False) is None +# assert t.pub_share_description(False) is None + +# def test03_oneparam_functions(): +# assert t.set_unitname("Foo") == 0 + \ No newline at end of file diff --git a/lang/python/nanobind_core/tests/clientserver_test/clientserver_test.py b/lang/python/nanobind_core/tests/clientserver_test/clientserver_test.py new file mode 100644 index 0000000000..781d23fb53 --- /dev/null +++ b/lang/python/nanobind_core/tests/clientserver_test/clientserver_test.py @@ -0,0 +1,111 @@ +import unittest +import nanobind_core as ecal +import time +from threading import Event + +class AtomicSignalable: + def __init__(self, initial=0): + self.value = initial + self.event = Event() + + def increment(self): + self.value += 1 + self.event.set() + + def get(self): + return self.value + + def wait_for(self, condition, timeout): + start_time = time.time() + while not condition(self.value): + if time.time() - start_time > timeout: + break + self.event.wait(timeout) + return condition(self.value) + +class TestClientServer(unittest.TestCase): + + def test_client_connect_event(self): + ecal.initialize() + + client = ecal.ServiceClient("service") + + event_connected_fired = AtomicSignalable(0) + event_disconnected_fired = AtomicSignalable(0) + + def client_event_callback(name, data): + if data.type == ecal.eCAL_Client_Event.client_event_connected: + print("event connected fired") + event_connected_fired.increment() + elif data.type == ecal.eCAL_Client_Event.client_event_disconnected: + print("event disconnected fired") + event_disconnected_fired.increment() + + client.add_event_callback(ecal.eCAL_Client_Event.client_event_connected, client_event_callback) + client.add_event_callback(ecal.eCAL_Client_Event.client_event_disconnected, client_event_callback) + + time.sleep(1) + self.assertEqual(event_connected_fired.get(), 0) + self.assertEqual(event_disconnected_fired.get(), 0) + + server1 = ecal.ServiceServer("service") + + event_connected_fired.wait_for(lambda v: v >= 1, 5) + self.assertEqual(event_connected_fired.get(), 1) + self.assertEqual(event_disconnected_fired.get(), 0) + + server2 = ecal.ServiceServer("service") + + event_connected_fired.wait_for(lambda v: v >= 2, 5) + self.assertEqual(event_connected_fired.get(), 2) + self.assertEqual(event_disconnected_fired.get(), 0) + + event_disconnected_fired.wait_for(lambda v: v >= 2, 20) + self.assertEqual(event_connected_fired.get(), 2) + self.assertEqual(event_disconnected_fired.get(), 2) + + ecal.finalize() + + def test_server_connect_event(self): + ecal.initialize() + + server = ecal.ServiceServer("service") + + event_connected_fired = AtomicSignalable(0) + event_disconnected_fired = AtomicSignalable(0) + + def event_callback(name, data): + if data.type == ecal.eCAL_Server_Event.server_event_connected: + print("event connected fired") + event_connected_fired.increment() + elif data.type == ecal.eCAL_Server_Event.server_event_disconnected: + print("event disconnected fired") + event_disconnected_fired.increment() + + server.add_event_callback(ecal.eCAL_Server_Event.server_event_connected, event_callback) + server.add_event_callback(ecal.eCAL_Server_Event.server_event_disconnected, event_callback) + + time.sleep(1) + self.assertEqual(event_connected_fired.get(), 0) + self.assertEqual(event_disconnected_fired.get(), 0) + + client1 = ecal.ServiceClient("service") + + event_connected_fired.wait_for(lambda v: v >= 1, 5) + self.assertEqual(event_connected_fired.get(), 1) + self.assertEqual(event_disconnected_fired.get(), 0) + + client2 = ecal.ServiceClient("service") + + time.sleep(2) + self.assertEqual(event_connected_fired.get(), 1) + self.assertEqual(event_disconnected_fired.get(), 0) + + event_disconnected_fired.wait_for(lambda v: v >= 1, 10) + self.assertEqual(event_connected_fired.get(), 1) + self.assertEqual(event_disconnected_fired.get(), 1) + + ecal.finalize() + +if __name__ == '__main__': + unittest.main() diff --git a/lang/python/nanobind_core/tests/core_test/core_test.py b/lang/python/nanobind_core/tests/core_test/core_test.py new file mode 100644 index 0000000000..93557040c1 --- /dev/null +++ b/lang/python/nanobind_core/tests/core_test/core_test.py @@ -0,0 +1,101 @@ +import unittest +import ctypes +import nanobind_core as eCAL + +ECAL_VERSION = "v6.0.0-nightly-52-g063aa0199-dirty" # Define these constants as per your eCAL version +ECAL_DATE = "24.05.2024" +ECAL_VERSION_MAJOR = 6 # Define these constants as per your eCAL version +ECAL_VERSION_MINOR = 0 +ECAL_VERSION_PATCH = 0 + +class TestCoreCppCore(unittest.TestCase): + def test_get_version(self): + # Get eCAL version string + self.assertEqual(ECAL_VERSION, eCAL.get_version_string()) + + # Get eCAL version date + self.assertEqual(ECAL_DATE, eCAL.get_version_date()) + + # Get eCAL version as separated integer values + status, major, minor, patch = eCAL.get_version() + self.assertEqual(0, status) + + self.assertEqual(ECAL_VERSION_MAJOR, major) + self.assertEqual(ECAL_VERSION_MINOR, minor) + self.assertEqual(ECAL_VERSION_PATCH, patch) + + def test_initialize_finalize(self): + # Is eCAL API initialized? + self.assertEqual(0, eCAL.is_initialized()) + + # Initialize eCAL API + self.assertEqual(0, eCAL.initialize()) + + # Is eCAL API initialized? + self.assertEqual(1, eCAL.is_initialized()) + + # Initialize eCAL API again, we expect return value 1 for yet initialized + self.assertEqual(1, eCAL.initialize()) + + # Finalize eCAL API, we expect return value 0 even if it will not be really finalized because it's 2 times initialized and 1 time finalized + self.assertEqual(0, eCAL.finalize(0)) + + # Is eCAL API initialized? Yes, it's still initialized + self.assertEqual(1, eCAL.is_initialized()) + + # Finalize eCAL API, we expect return value 0 because now it will be finalized + self.assertEqual(0, eCAL.finalize(0)) + + # Is eCAL API initialized? No + self.assertEqual(0, eCAL.is_initialized()) + + # Finalize eCAL API, we expect return value 1 because it was finalized before + self.assertEqual(1, eCAL.finalize(0)) + + def test_multiple_initialize_finalize(self): + # Try to initialize/finalize multiple times + for _ in range(4): + # Initialize eCAL API + self.assertEqual(0, eCAL.initialize()) + + # Finalize eCAL API + self.assertEqual(0, eCAL.finalize(0)) + + def test_set_get_unit_name(self): + # Initialize eCAL API with empty unit name (eCAL will use process name as unit name) + self.assertEqual(0, eCAL.initialize()) + + # Is eCAL API initialized? + self.assertEqual(1, eCAL.is_initialized()) + + # Set unit name + self.assertEqual(0, eCAL.set_unitname("unit name")) + + # Set None unit name + with self.assertRaises(TypeError): + eCAL.set_unitname(None) + + # Set empty unit name + self.assertEqual(-1, eCAL.set_unitname("")) + + # Finalize eCAL API, we expect return value 0 because it will be finalized + self.assertEqual(0, eCAL.finalize(0)) + + def test_ecal_ok(self): + # Check uninitialized eCAL, should not be okay + self.assertEqual(0, eCAL.ok()) + + # Initialize eCAL API + self.assertEqual(0, eCAL.initialize()) + + # Check initialized eCAL, should be okay + self.assertEqual(1, eCAL.ok()) + + # Finalize eCAL API, we expect return value 0 because it will be finalized + self.assertEqual(0, eCAL.finalize(0)) + + # Check finalized eCAL, should not be okay + self.assertEqual(0, eCAL.ok()) + +if __name__ == '__main__': + unittest.main() diff --git a/lang/python/nanobind_core/tests/pubsub_test/pubsub_test.py b/lang/python/nanobind_core/tests/pubsub_test/pubsub_test.py new file mode 100644 index 0000000000..496f46fbf9 --- /dev/null +++ b/lang/python/nanobind_core/tests/pubsub_test/pubsub_test.py @@ -0,0 +1,123 @@ +import unittest +from unittest.mock import patch, call +import nanobind_core as ecal_core +import time + +PAYLOAD_SIZE = 25 +CMN_REGISTRATION_REFRESH = 1000 +DATA_FLOW_TIME = 500 + +# Global variable to store the callback received bytes +g_callback_received_bytes = 0 + +def create_payload(size): + s = "Hello World " + while len(s) < size: + s += s + s = s[:size] + return s + +def on_receive(topic_name, msg, time): + global g_callback_received_bytes + g_callback_received_bytes = len(msg) + +class TestECALPubSub(unittest.TestCase): + def setUp(self): + ecal_core.initialize() + ecal_core.enable_loopback(True) + self.pub = ecal_core.Publisher("foo") + self.sub = ecal_core.Subscriber("foo") + self.send_s = create_payload(PAYLOAD_SIZE) + self.recv_s = "" + + def tearDown(self): + self.pub.destroy() + self.sub.destroy() + ecal_core.finalize(0) + + def test_simple_message1(self): + # Let's match them + time.sleep(2 * CMN_REGISTRATION_REFRESH / 1000) # Convert milliseconds to seconds + + # Send content + self.assertEqual(len(self.send_s), self.pub.send(self.send_s,0)) + + # Receive content with DATA_FLOW_TIME ms timeout + self.recv_s = self.sub.receive(50) + self.assertEqual(len(self.send_s), len(self.recv_s)) + + # Receive content with DATA_FLOW_TIME ms timeout + # should return because no new publishing + self.recv_s = self.sub.receive(50) + self.assertEqual(0, len(self.recv_s)) + + def test_simple_message2(self): + # Let's match them + time.sleep(2 * CMN_REGISTRATION_REFRESH / 1000) # Convert milliseconds to seconds + + # Send content + self.assertEqual(len(self.send_s), self.pub.send(self.send_s,0)) + + # Receive content with DATA_FLOW_TIME ms timeout + self.recv_s = self.sub.receive(50) + self.assertEqual(len(self.send_s), len(self.recv_s)) + + def test_simple_message_cb(self): + global g_callback_received_bytes + + # Add callback + self.sub.add_receive_callback(on_receive) + + # Let them match + time.sleep(2 * CMN_REGISTRATION_REFRESH / 1000) + + # Send content + g_callback_received_bytes = 0 + self.assertEqual(len(self.send_s), self.pub.send(self.send_s, 0)) + + # Let the data flow + time.sleep(DATA_FLOW_TIME / 1000) + + # Check callback receive + self.assertEqual(len(self.send_s), g_callback_received_bytes) + + # Remove receive callback + self.sub.rem_receive_callback() + + # Send content + g_callback_received_bytes = 0 + self.assertEqual(len(self.send_s), self.pub.send(self.send_s, 0)) + + # Let the data flow + time.sleep(DATA_FLOW_TIME / 1000) + + # Check callback receive + self.assertEqual(0, g_callback_received_bytes) + + # Add callback again + self.sub.add_receive_callback(on_receive) + + # Send content + g_callback_received_bytes = 0 + self.assertEqual(len(self.send_s), self.pub.send(self.send_s, 0)) + + # Let the data flow + time.sleep(DATA_FLOW_TIME / 1000) + + # Check callback receive + self.assertEqual(len(self.send_s), g_callback_received_bytes) + + self.sub.destroy() + + # Send content + g_callback_received_bytes = 0 + self.assertEqual(len(self.send_s), self.pub.send(self.send_s, 0)) + + # Let the data flow + time.sleep(DATA_FLOW_TIME / 1000) + + # Check callback receive + self.assertEqual(0, g_callback_received_bytes) + +if __name__ == "__main__": + unittest.main() diff --git a/samples/python/nanobind_wrappers/minimal_service/nb_minimal_srv_client.py b/samples/python/nanobind_wrappers/minimal_service/nb_minimal_srv_client.py new file mode 100644 index 0000000000..3fbcaee390 --- /dev/null +++ b/samples/python/nanobind_wrappers/minimal_service/nb_minimal_srv_client.py @@ -0,0 +1,69 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +from pickle import TRUE +import sys +import time + +import nanobind_core as ecal_core + + # define the client response callback to catch server responses +def client_resp_callback(service_info, response): + if (service_info["call_state"] == "call_state_executed"): + print("'DemoService' method '{}' responded : '{}'".format(service_info["method_name"], response)) + print() + else: + print("server {} response failed, error : '{}'".format(service_info["host_name"], service_info["error_msg"])) + print() + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create a client for the "DemoService" service + client = ecal_core.ServiceClient("DemoService") + + # and add it to the client + client.add_response_callback(client_resp_callback) + + # idle and call service methods + i = 0 + while(ecal_core.ok()): + i = i + 1 + # call foo + request = bytes("hello foo {}".format(i), "ascii") + print("'DemoService' method 'foo' requested with : {}".format(request)) + client.call("foo", "request", 1234) + time.sleep(0.5) + # call ping + request = bytes("ping number {}".format(i), "ascii") + print("'DemoService' method 'ping' requested with : {}".format(request)) + client.call("ping", "request", 1234) + time.sleep(0.5) + + # destroy client + client.destroy() + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() diff --git a/samples/python/nanobind_wrappers/minimal_service/nb_minimal_srv_server.py b/samples/python/nanobind_wrappers/minimal_service/nb_minimal_srv_server.py new file mode 100644 index 0000000000..e6f90011ce --- /dev/null +++ b/samples/python/nanobind_wrappers/minimal_service/nb_minimal_srv_server.py @@ -0,0 +1,66 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +import sys +import time + +import nanobind_core as ecal_core + +# define the server method "foo" function +def foo_req_callback(method_name, req_type, resp_type, request): + print("'DemoService' method '{}' called with {}".format(method_name, request)) + #return True #, bytes("thank you for calling foo :-)", "ascii") + return 0, "pong" + +# define the server method "ping" function +def ping_req_callback(method_name, req_type, resp_type, request): + print("'DemoService' method '{}' called with {}".format(method_name, request)) + return 0, bytes("pong", "ascii") + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # initialize eCAL API + # ecal_core.initialize(sys.argv, "py_minimal_service_server") + + # set process state + # ecal_core.set_process_state(1, 1, "I feel good") + + # create a server for the "DemoService" service + server = ecal_core.ServiceServer("DemoService") + + # define the server methods and connect them to the callbacks + server.add_method_callback("foo", "string", "string", foo_req_callback) + server.add_method_callback("ping", "ping_type", "pong_type", ping_req_callback) + + # idle + while(ecal_core.ok()): + time.sleep(1.0) + + # destroy server + server.destroy() + + # finalize eCAL API + server.finalize() + +if __name__ == "__main__": + main() diff --git a/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_rec.py b/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_rec.py new file mode 100644 index 0000000000..6f9d8e1c0d --- /dev/null +++ b/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_rec.py @@ -0,0 +1,24 @@ +import sys + +import nanobind_core as ecal_core + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create subscriber + sub = ecal_core.NBSubscriber("Hello") + + # receive messages + while ecal_core.ok(): + msg = sub.receive() + print("Received: {} ".format(msg)) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_rec_cb.py b/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_rec_cb.py new file mode 100644 index 0000000000..a6c24e0647 --- /dev/null +++ b/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_rec_cb.py @@ -0,0 +1,48 @@ +# ========================= eCAL LICENSE ================================= +# +# Copyright (C) 2016 - 2024 Continental Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ========================= eCAL LICENSE ================================= + +import sys +import time + +import nanobind_core as ecal_core + +# eCAL receive callback +def callback(topic_name, msg, time): + print("Received: {} ms {}".format(time, msg)) + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create subscriber and connect callback + sub = ecal_core.Subscriber("Hello") + sub.add_receive_callback(callback) + + # idle main thread + while ecal_core.ok(): + time.sleep(0.1) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main() + diff --git a/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_snd.py b/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_snd.py new file mode 100644 index 0000000000..79a9ae2453 --- /dev/null +++ b/samples/python/nanobind_wrappers/minimal_snd_rec/nb_minimal_snd.py @@ -0,0 +1,30 @@ +import sys +import time + +import nanobind_core as ecal_core + +def main(): + # print eCAL version and date + print("eCAL {} ({})\n".format(ecal_core.get_version_string(), ecal_core.get_version_date())) + + # initialize eCAL API + ecal_core.initialize() + + # create publisher + pub = ecal_core.Publisher("Hello") + msg = "HELLO WORLD FROM PYTHON" + + # send messages + i = 0 + while ecal_core.ok(): + i = i + 1 + current_message = "{} {:6d}".format(msg, i) + print("Sending: {}".format(current_message)) + pub.send(current_message,1234) + time.sleep(0.5) + + # finalize eCAL API + ecal_core.finalize() + +if __name__ == "__main__": + main()