diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..33c46b1d7f44240b92c9ea473de6503432a2dbff --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "travodds_rust" +version = "0.1.0" +edition = "2024" +build = "build.rs" + +[dependencies] + +[build-dependencies] +bindgen = "*" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..5153e190c3a66f2dc3e36bf1015cc360d03f33f0 --- /dev/null +++ b/build.rs @@ -0,0 +1,94 @@ +use std::env; +use std::path::PathBuf; +use bindgen::callbacks::{ParseCallbacks, EnumVariantValue, ItemInfo}; + +#[derive(Debug)] +struct RenameCallbacks; + +impl ParseCallbacks for RenameCallbacks { + fn item_name(&self, original_item_name: ItemInfo<'_>) -> Option { + let mut renamed = String::from(original_item_name.name); + if original_item_name.name == "DDS_CString" { + renamed = "DDSCString".to_string(); + } + // 替换DDS_LongLong为LLong + renamed = renamed.replace("DDS_LongLong", "LLong"); + // 替换DDS_LongDouble为LDouble + renamed = renamed.replace("DDS_LongDouble", "LDouble"); + // 替换DDS_为空 + renamed = renamed.replace("DDS_", ""); + // 替换_iterater为Iterator + renamed = renamed.replace("_iterator", "Iterator"); + Some(renamed) + } + + fn enum_variant_name( + &self, + _enum_name: Option<&str>, + original_variant_name: &str, + _variant_value: EnumVariantValue, + ) -> Option { + Some(match original_variant_name { + // 完全匹配重命名 + + // 模式匹配重命名 + s if s.starts_with("DDS_") => { + s.trim_start_matches("DDS_").to_string() + }, + + // 保留其他名称不变 + _ => original_variant_name.to_string(), + }) + } +} + +fn main() { + // Get travodds_c library path from environment variable + let travodds_c_path = env::var("TRAVODDS_C_PATH").unwrap_or_else(|_| { + println!("Please set the TRAVODDS_C_PATH environment variable to the path of the travodds_c library."); + std::process::exit(1); + }); + // Tell cargo to look for shared libraries in the specified directory + println!("cargo:rustc-link-search={}/lib", travodds_c_path); + + // Link to travodds_c library (update as needed) + if cfg!(debug_assertions) { + println!("cargo:rustc-link-lib=travoddscd"); + } else { + // Release mode link travodds + println!("cargo:rustc-link-lib=travodds"); + } + + // Add include path for travodds_c headers + let travodds_include = format!("{}/include", travodds_c_path); + + let bindings = bindgen::Builder::default() + // Use all headers in travodds_c/include + .clang_arg(format!("-I{}", travodds_include)) + .header(format!("{}/dds_basetype.h", travodds_include)) + .header(format!("{}/dds_c_string.h", travodds_include)) + .header(format!("{}/dds_c_wstring.h", travodds_include)) + .header(format!("{}/dds_builtin_topic.h", travodds_include)) + .header(format!("{}/dds_infrastructure.h", travodds_include)) + .header(format!("{}/dds_domain_participant_factory.h", travodds_include)) + .header(format!("{}/dds_domain_participant.h", travodds_include)) + .header(format!("{}/dds_topic.h", travodds_include)) + .header(format!("{}/dds_typesupport.h", travodds_include)) + .header(format!("{}/dds_publisher.h", travodds_include)) + .header(format!("{}/dds_subscriber.h", travodds_include)) + .header(format!("{}/dds_datawriter.h", travodds_include)) + .header(format!("{}/dds_datareader.h", travodds_include)) + .header(format!("{}/dds_waitset.h", travodds_include)) + .header(format!("{}/dds_condition.h", travodds_include)) + .rustified_enum(".*") + .parse_callbacks(Box::new(RenameCallbacks)) + .derive_default(true) + .generate() + .expect("Unable to generate bindings"); + + // Write the bindings to the src directory + let out_path = PathBuf::from(env::current_dir().unwrap()).join("src"); + bindings + .write_to_file(out_path.join("travodds.rs")) + .expect("Couldn't write bindings!"); +} \ No newline at end of file diff --git a/doc/README.MD b/doc/README.MD new file mode 100644 index 0000000000000000000000000000000000000000..62a8076ca621b7ef0e625a33fc37f4930eb52634 --- /dev/null +++ b/doc/README.MD @@ -0,0 +1,66 @@ +# travodds_rust + +## 1. 概述 + +本开发库为travodds开发库(C++)接口的rust语言封装库,使用本库使得用户能够在rust的工程中使用travodds。 + +## 2. 编译安装 + +- 安装依赖: + - [travodds核心库](https://gitee.com/agiros-dds/travodds.git); + - [travodds-c库](https://gitee.com/agiros-dds/travodds-c.git); + - rustup(>=1.87.0) + - Windows: [rustup-init.exe](https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe) + - Linux: `curl https://sh.rustup.rs -sSf | sh` + - libclang-dev + - Windows: [LLVM] + - Ubuntu: `apt install libclang-dev` + - CentOS: `yum install clang-devel` + +- `git clone https://gitee.com/agiros-dds/travodds-rust.git` +- 设置环境变量 + - cmd: `set TRAVODDS_C_PATH=/path/to/travodds_c && set TRAVODDS_PATH=/path/to/travodds` + - powershell: `$env:TRAVODDS_C_PATH="/path/to/travodds";$env:TRAVODDS_PATH="/path/to/travodds_c";` + - Linux: `export TRAVODDS_C_PATH=/path/to/travodds_c && EXPORT TRAVODDS_PATH=/path/to/travodds` +- 编译生成rust绑定:`cargo build` +- 编译成功后在src目录中: + - travodds.rs用于rust开发的travodds接口绑定; + +## 3. 使用示例 + +### 3.1. 源码结构 + +- 示例代码在example目录中; +- example_type.idl为示例IDL文件; +- 以下文件为编译器自动生成的文件: + - example_type.h + - example_type.cpp + - example_typeTypeSupport.h + - example_typeTypeSupport.cpp + - build.rs + - Cargo.toml(略有修改) +- 发送端示例代码:pub_example.rs +- 接收端示例代码:sub_example.rs + +### 3.2. 编译示例 + +- 设置环境变量:TRAVODDS_PATH、TRAVODDS_C_PATH +- `cargo build` +- 运行成功后在target/debug下会有pub_example/sub_example的可执行程序; + +### 3.3. 运行示例 + +- 发送端运行pub_example,观察到1s中发送一包序号递增的数据; +- 接收端运行sub_example,观察到1s中接收到一包序号递增的数据; + +## 4. 使用流程 + +- 前提:travodds、travodds_rust、travoddsgen安装完成; +- 定义IDL文件; +- 使用travoddsgen生成rust语言接口,详细参见travoddsgen手册; +- 将生成的代码生成类型开发库; +- 在业务工程用使用类型开发库以及本库进行接口进行开发; + +## 5. 接口说明 + +- TODO 待补充 diff --git a/example/Cargo.toml b/example/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..8a98f6b880e94717a2260b1440c59c9a2df90f66 --- /dev/null +++ b/example/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "example_type" +version = "0.1.0" +edition = "2024" +build = "build.rs" + +[[bin]] +name = "pub_example" +path = "pub_example.rs" + +[[bin]] +name = "sub_example" +path = "sub_example.rs" + +[dependencies] + +[build-dependencies] +cc = "1.0" +bindgen = "*" diff --git a/example/build.rs b/example/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..bb939b68ab804fbf8c75cf7843cfb68e42d19e02 --- /dev/null +++ b/example/build.rs @@ -0,0 +1,59 @@ +use std::env; +use std::path::PathBuf; +use bindgen::callbacks::{ParseCallbacks, ItemInfo}; + +#[derive(Debug)] +struct RenameCallbacks; + +impl ParseCallbacks for RenameCallbacks { + fn item_name(&self, original_item_name: ItemInfo<'_>) -> Option { + let mut renamed = String::from(original_item_name.name); + if original_item_name.name == "DDS_CString" { + renamed = "DDSCString".to_string(); + } + renamed = renamed.replace("DDS_LongLong", "LLong"); + renamed = renamed.replace("DDS_LongDouble", "LDouble"); + renamed = renamed.replace("DDS_", ""); + renamed = renamed.replace("_iterator", "Iterator"); + Some(renamed) + } +} + +fn main() { + let travodds_c_path = env::var("TRAVODDS_C_PATH").unwrap_or_else(|_| { + println!("Please set the TRAVODDS_C_PATH environment variable to the path of the travodds_c library."); + std::process::exit(1); + }); + let travodds_path = env::var("TRAVODDS_PATH").unwrap_or_else(|_| { + println!("Please set the TRAVODDS_PATH environment variable to the path of the travodds_c library."); + std::process::exit(1); + }); + println!("cargo:rustc-link-search=native={}/lib", travodds_c_path); + println!("cargo:rustc-link-search=native={}/lib", travodds_path); + println!("cargo:rustc-link-lib=static=travoddscz"); + println!("cargo:rustc-link-lib=static=travoddsstatic"); + println!("cargo:rustc-link-lib=static=stdc++"); + + cc::Build::new() + .file("example_type.cpp") + .file("example_typeTypeSupport.cpp") + .include(format!("{}/include", travodds_c_path)) + .include(format!("{}/include", travodds_path)) + .compile("example_type"); + + let bindings = bindgen::Builder::default() + .clang_arg(format!("-I{}/include", travodds_c_path)) + .header("example_type.h") + .header("example_typeTypeSupport.h") + .allowlist_file(".*example_type.h") + .allowlist_file(".*example_typeTypeSupport.h") + .allowlist_recursively(false) + .parse_callbacks(Box::new(RenameCallbacks)) + .generate() + .expect("Unable to generate bindings"); + let out_path = PathBuf::from(env::current_dir().unwrap()); + bindings + .write_to_file(out_path.join("example_type.rs")) + .expect("Couldn't write example_type bindings!"); + println!("cargo:rustc-link-lib=static=example_type"); +} diff --git a/example/example_type.cpp b/example/example_type.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5141533460fbd3ddf317f78d6f126e3deb089912 --- /dev/null +++ b/example/example_type.cpp @@ -0,0 +1,28 @@ +#include "example_type.h" +#include "dds_basetype.h" +#include "dds_c_string.h" +#include "dds_c_sequence.cpp" +#include "dds_c_map.cpp" + +#ifdef __cplusplus +extern "C" { +#endif + +DDSCSequenceImpl(example_type); + +example_type* example_type_create() { + return new example_type(); +} + +void example_type_destroy(example_type* obj) { + delete obj; +} + +example_type* example_type_copy(example_type* obj, const example_type* other) { + *obj = *other; + return obj; +} + +#ifdef __cplusplus +} +#endif diff --git a/example/example_type.h b/example/example_type.h new file mode 100644 index 0000000000000000000000000000000000000000..6ed38f590288b858dd141c12543e4af5d5908826 --- /dev/null +++ b/example/example_type.h @@ -0,0 +1,29 @@ +#ifndef example_type_H +#define example_type_H + +#include "dds_c_sequence.h" +#include "dds_c_map.h" +#include "dds_c_string.h" +#include "dds_c_wstring.h" +#include "dds_basetype.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct example_type { + DDS_CString color; + DDS_Long x; + DDS_Long y; +} example_type; + +DDSCSequence(example_type); + +example_type* example_type_create(); +void example_type_destroy(example_type* self); +example_type* example_type_copy(example_type* self, const example_type* other); + +#ifdef __cplusplus +} +#endif +#endif /* example_type_H */ diff --git a/example/example_type.idl b/example/example_type.idl new file mode 100644 index 0000000000000000000000000000000000000000..61eadc915bdd91dd7b92feae174b605f9cb9047e --- /dev/null +++ b/example/example_type.idl @@ -0,0 +1,6 @@ +struct example_type +{ + string<128> color; + long x; + long y; +}; \ No newline at end of file diff --git a/example/example_typeTypeSupport.cpp b/example/example_typeTypeSupport.cpp new file mode 100644 index 0000000000000000000000000000000000000000..68a3b0427692392acb2e986246f8f8230e97e6e8 --- /dev/null +++ b/example/example_typeTypeSupport.cpp @@ -0,0 +1,175 @@ +#include "example_type.h" +#include "dcps/topic/typesupport.h" + +USING_AGIDDS_NAMESPACE + +#ifdef __cplusplus +extern "C" { +#endif + +class example_typeTypeSupport : public AGIDDS::TypeSupport { +public: + static example_typeTypeSupport* get_instance(); + + virtual void* create_data() override; + + virtual void delete_data(void* data) override; + + virtual int copy_data(void* dst, void* src) override; + + virtual unsigned int get_serialized_data_size(void* data, unsigned int currentAlignment) override; + + virtual unsigned int get_max_serialized_data_size(void* data, unsigned int currentAlignment) override; + + virtual int serialize_data(void* data, AGIDDSCdrSerializer* cdr, int endian) override; + + virtual int deserialize_data(void* data, AGIDDSCdrDeserializer* cdr, int endian) override; + + virtual AGIDDS::TypeObject* get_typeobject() override; + + virtual AGIDDS::ReturnCode_t get_instancehandle(void* data, AGIDDSCdrSerializer* cdr, AGIDDS::InstanceHandle_t& iHandle, bool forceMd5 = false) override; + + virtual bool has_key() override; + + virtual const char* get_typename() override; + + virtual int MakeKey(const void* data, AGIDDS::InstanceHandle_t& iHandle, bool forceMd5 = false) override; + + int serialize_key(void* data, AGIDDSCdrSerializer* cdr, int endian); + +private: + example_typeTypeSupport() = default; +}; + +example_typeTypeSupport* example_typeTypeSupport::get_instance() { + static example_typeTypeSupport instance; + return &instance; +} + +void* example_typeTypeSupport::create_data() { + return new example_type(); +} + +void example_typeTypeSupport::delete_data(void* data) { + delete static_cast(data); +} + +int example_typeTypeSupport::copy_data(void* dst, void* src) { + example_type* dstData = static_cast(dst); + example_type* srcData = static_cast(src); + *dstData = *srcData; + return 0; +} + +unsigned int example_typeTypeSupport::get_serialized_data_size(void* data, unsigned int currentAlignment) { + example_type* structData = static_cast(data); + unsigned int initialAlignment = currentAlignment; + unsigned int tmpAlignment = 0; + currentAlignment += AGIDDSCdrSerializer::getStringSize(structData->color.size() + 1, currentAlignment); + currentAlignment += AGIDDSCdrSerializer::getBaseTypeSize(sizeof(DDS_Long), currentAlignment); + currentAlignment += AGIDDSCdrSerializer::getBaseTypeSize(sizeof(DDS_Long), currentAlignment); + return currentAlignment - initialAlignment; +} + +unsigned int example_typeTypeSupport::get_max_serialized_data_size(void* data, unsigned int currentAlignment) { + example_type* structData = static_cast(data); + unsigned int initialAlignment = currentAlignment; + unsigned int tmpAlignment = 0; + currentAlignment += AGIDDSCdrSerializer::getStringSize(128, currentAlignment); + currentAlignment += AGIDDSCdrSerializer::getBaseTypeSize(sizeof(DDS_Long), currentAlignment); + currentAlignment += AGIDDSCdrSerializer::getBaseTypeSize(sizeof(DDS_Long), currentAlignment); + return currentAlignment - initialAlignment; +} + +int example_typeTypeSupport::serialize_data(void* data, AGIDDSCdrSerializer* cdr, int endian) { + example_type* structData = static_cast(data); + uint32_t tmpLength = 0; + if (!cdr->serializeString(structData->color)) { + fprintf(stderr, "Serialization failed for field: structData->color\n"); + return -1; + } + if (!cdr->serializeBaseType(structData->x)) { + fprintf(stderr, "Serialization failed for field: structData->x\n"); + return -1; + } + if (!cdr->serializeBaseType(structData->y)) { + fprintf(stderr, "Serialization failed for field: structData->y\n"); + return -1; + } + return 0; +} + +int example_typeTypeSupport::deserialize_data(void* data, AGIDDSCdrDeserializer* cdr, int endian) { + example_type* structData = static_cast(data); + unsigned int tmpLength = 0; + char tmpCharEnum = 0; + short tmpShortEnum = 0; + int tmpIntEnum = 0; + if (!cdr->deserializeString(structData->color)) { + fprintf(stderr, "Deserialization failed for field: structData->color\n"); + return -1; + } + if (!cdr->deserializeBaseType(structData->x)) { + fprintf(stderr, "Deserialization failed for field: structData->x\n"); + return -1; + } + if (!cdr->deserializeBaseType(structData->y)) { + fprintf(stderr, "Deserialization failed for field: structData->y\n"); + return -1; + } + return 0; +} + +TypeObject* example_typeTypeSupport::get_typeobject() { + return nullptr; +} + +int example_typeTypeSupport::serialize_key(void* data, AGIDDSCdrSerializer* cdr, int endian) { + example_type* structData = static_cast(data); + bool memberHasKey = false; + return 0; +} + +int example_typeTypeSupport::MakeKey(const void* data, InstanceHandle_t& iHandle, bool forceMd5) { + unsigned int serializedSize = get_serialized_data_size((void*)data, 0); + SerializedBuffer buffer; + buffer.buffer_size = serializedSize; + buffer.buffer = new char[buffer.buffer_size]; + AGIDDSCdrSerializer cdr(&buffer); + ReturnCode_t ret = get_instancehandle((void*)data, &cdr, iHandle, forceMd5); + delete[] buffer.buffer; + return ret == RETCODE_OK ? 0 : -1; +} + +ReturnCode_t example_typeTypeSupport::get_instancehandle(void* data, AGIDDSCdrSerializer* cdr, InstanceHandle_t& iHandle, bool forceMd5) { + if (!has_key()) { + iHandle = HANDLE_NIL; + return RETCODE_OK; + } + int ret = serialize_key(data, cdr, forceMd5); + if (ret != 0) { + fprintf(stderr, "Failed to serialize key.\n"); + return RETCODE_ERROR; + } + if (!cdr->getKeyHash((char*)&iHandle, forceMd5)) { + fprintf(stderr, "Failed to get key hash\n"); + return RETCODE_ERROR; + } + return RETCODE_OK; +} + +bool example_typeTypeSupport::has_key() { + return false; +} + +const char* example_typeTypeSupport::get_typename() { + return "example_type"; +} + +void* example_typeTypeSupport_get_instance() { + return example_typeTypeSupport::get_instance(); +} + +#ifdef __cplusplus +} +#endif diff --git a/example/example_typeTypeSupport.h b/example/example_typeTypeSupport.h new file mode 100644 index 0000000000000000000000000000000000000000..ef4d1e6a5ddc36e8be9dbdcbaa01af37916184ef --- /dev/null +++ b/example/example_typeTypeSupport.h @@ -0,0 +1,14 @@ +#ifndef example_typeTypeSupport_H +#define example_typeTypeSupport_H + + +#ifdef __cplusplus +extern "C" { +#endif + +void* example_typeTypeSupport_get_instance(); + +#ifdef __cplusplus +} +#endif +#endif /* example_typeTypeSupport_H */ diff --git a/example/pub_example.rs b/example/pub_example.rs new file mode 100644 index 0000000000000000000000000000000000000000..f37ff6ce14b8e0efd456bfc3eeccdfabe6ae1309 --- /dev/null +++ b/example/pub_example.rs @@ -0,0 +1,122 @@ +use std::{ffi::CString, ptr, thread, time::Duration}; + +include!("../src/travodds.rs"); +include!("example_type.rs"); + +fn main() { + unsafe { + // 1. 获取 DomainParticipantFactory 实例 + let factory = DomainParticipantFactory_get_instance(); + if factory.is_null() { + println!("Failed to get DomainParticipantFactory instance"); + return; + } + + // 2. 创建 DomainParticipant + let participant = DomainParticipantFactory_create_participant( + factory, + 0, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if participant.is_null() { + println!("Failed to create DomainParticipant"); + return; + } + + // 3. 注册类型 + let type_name = CString::new("example_type").unwrap(); + let mut ts = example_typeTypeSupport_get_instance(); + let ret = DomainParticipant_registe_type(participant, type_name.as_ptr(), ts); + if ret != RETCODE_OK { + println!("Failed to register type"); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 4. 创建 Topic + let topic_name = CString::new("example_topic").unwrap(); + let topic = DomainParticipant_create_topic( + participant, + topic_name.as_ptr(), + type_name.as_ptr(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if topic.is_null() { + println!("Failed to create Topic"); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 5. 创建 Publisher + let publisher = DomainParticipant_create_publisher( + participant, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if publisher.is_null() { + println!("Failed to create Publisher"); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 6. 创建 DataWriter + let writer = Publisher_create_datawriter( + publisher, + topic, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if writer.is_null() { + println!("Failed to create DataWriter"); + DomainParticipant_delete_publisher(participant, publisher); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 7. 构造数据并周期性发送 + let mut data = example_type_create(); + DDSCString_assign_cstr(&mut (*data).color, CString::new("red").unwrap().as_ptr()); + (*data).x = 1; + (*data).y = 2; + + // 转化为 void* 指针 + let data_ptr = data as *mut std::ffi::c_void; + + let mut handle = DataWriter_register_instance(writer, data_ptr); + + println!("Start sending data every 1s..."); + for i in 0..100 { + (*data).x = i + 1; + let ret = DataWriter_write(writer, data_ptr, &mut handle); + if ret != RETCODE_OK { + println!("Failed to write data at x={}", (*data).x); + } else { + // 获取 color 字符串 + let color_ptr = DDSCString_c_str(&(*data).color); + let color = if !color_ptr.is_null() { + std::ffi::CStr::from_ptr(color_ptr).to_string_lossy().into_owned() + } else { + String::from("") + }; + println!("Data written: color={}, x={}, y={}", color, (*data).x, (*data).y); + } + thread::sleep(Duration::from_secs(1)); + } + + Publisher_delete_datawriter(publisher, writer); + DomainParticipant_delete_publisher(participant, publisher); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + DomainParticipantFactory_finalize_instance(); + + example_type_destroy(data); + } +} \ No newline at end of file diff --git a/example/sub_example.rs b/example/sub_example.rs new file mode 100644 index 0000000000000000000000000000000000000000..0020731d8e430ff2419693536af9604f54956bff --- /dev/null +++ b/example/sub_example.rs @@ -0,0 +1,125 @@ +use std::{ffi::CString, ptr, thread, time::Duration}; + +include!("../src/travodds.rs"); +include!("example_type.rs"); + +fn main() { + unsafe { + // 1. 获取 DomainParticipantFactory 实例 + let factory = DomainParticipantFactory_get_instance(); + if factory.is_null() { + println!("Failed to get DomainParticipantFactory instance"); + return; + } + + // 2. 创建 DomainParticipant + let participant = DomainParticipantFactory_create_participant( + factory, + 0, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if participant.is_null() { + println!("Failed to create DomainParticipant"); + return; + } + + // 3. 注册类型 + let type_name = CString::new("example_type").unwrap(); + let ts = example_typeTypeSupport_get_instance(); + let ret = DomainParticipant_registe_type(participant, type_name.as_ptr(), ts); + if ret != RETCODE_OK { + println!("Failed to register type"); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 4. 创建 Topic + let topic_name = CString::new("example_topic").unwrap(); + let topic = DomainParticipant_create_topic( + participant, + topic_name.as_ptr(), + type_name.as_ptr(), + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if topic.is_null() { + println!("Failed to create Topic"); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + let topic_desc = Topic_as_topicdescription(topic); + if topic_desc.is_null() { + println!("Failed to get TopicDescription"); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 5. 创建 Subscriber + let subscriber = DomainParticipant_create_subscriber( + participant, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if subscriber.is_null() { + println!("Failed to create Subscriber"); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 6. 创建 DataReader + let reader = Subscriber_create_datareader( + subscriber, + topic_desc, + ptr::null_mut(), + ptr::null_mut(), + 0, + ); + if reader.is_null() { + println!("Failed to create DataReader"); + DomainParticipant_delete_subscriber(participant, subscriber); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + return; + } + + // 7. 等待数据 + let mut data = example_type_create(); + + let mut data_ptr = data as *mut std::ffi::c_void; + + for _ in 0..1000 { + let mut sample_info = SampleInfo::default(); + let ret = DataReader_take_next_sample(reader, data_ptr, &mut sample_info); + if ret == RETCODE_OK { + // 获取 color 字符串 + let color_ptr = DDSCString_c_str(&(*data).color); + let color = if !color_ptr.is_null() { + std::ffi::CStr::from_ptr(color_ptr).to_string_lossy().into_owned() + } else { + String::from("") + }; + println!("Received data: color={}, x={}, y={}", color, (*data).x, (*data).y); + } else if ret == RETCODE_NO_DATA { + println!("No data available"); + } else if ret == RETCODE_ERROR { + println!("Failed to take data"); + } + thread::sleep(Duration::from_secs(1)); + } + + Subscriber_delete_datareader(subscriber, reader); + DomainParticipant_delete_subscriber(participant, subscriber); + DomainParticipant_delete_topic(participant, topic); + DomainParticipantFactory_delete_participant(factory, participant); + DomainParticipantFactory_finalize_instance(); + + example_type_destroy(data); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..5e2ca512448a9219c4384e6cabd5157e0b81e707 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +include!("travodds.rs");