From d0cf4d1b388574c3c88cc29256dce8293128f249 Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Sat, 11 Jul 2026 08:46:08 +0200 Subject: [PATCH 1/7] feat: Add unsafe bindings for the Device Data Hub API Device Data Hub is the designated replacement for the Message Broker API, which is deprecated and will be removed in AXIS OS 13.0. The bindings are generated from the C headers the same way as for `mdb-sys`. Constants that the C headers define as object-like macros with casts are transcribed manually because bindgen cannot evaluate them. --- .devcontainer/Dockerfile | 2 +- .devhost/install-sdk.sh | 4 +- Cargo.lock | 9 + Cargo.toml | 6 +- crates/datahub-sys/Cargo.toml | 13 + crates/datahub-sys/build.rs | 29 ++ crates/datahub-sys/src/bindings.rs | 684 +++++++++++++++++++++++++++++ crates/datahub-sys/src/lib.rs | 69 +++ crates/datahub-sys/wrapper.h | 4 + 9 files changed, 815 insertions(+), 5 deletions(-) create mode 100644 crates/datahub-sys/Cargo.toml create mode 100644 crates/datahub-sys/build.rs create mode 100644 crates/datahub-sys/src/bindings.rs create mode 100644 crates/datahub-sys/src/lib.rs create mode 100644 crates/datahub-sys/wrapper.h diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a55bb847..202c1783 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -3,7 +3,7 @@ ARG SDK=acap-native-sdk # Keep in sync with `install-sdk.sh` and `on-host-workflow.yml`. ARG UBUNTU_VERSION=24.04 # Keep in sync with `install-sdk.sh`. -ARG VERSION=12.1.0 +ARG VERSION=12.11.0 ARG BASE_IMAGE=debian:trixie-20260223 FROM ${REPO}/${SDK}:${VERSION}-aarch64-ubuntu${UBUNTU_VERSION} AS sdk-aarch64 diff --git a/.devhost/install-sdk.sh b/.devhost/install-sdk.sh index 7f6537b3..d957fd63 100755 --- a/.devhost/install-sdk.sh +++ b/.devhost/install-sdk.sh @@ -5,7 +5,7 @@ set -eux DIRECTORY="${1}" # Keep version in sync with `Dockerfile`. -docker run axisecp/acap-native-sdk:12.1.0-armv7hf-ubuntu24.04 tar \ +docker run axisecp/acap-native-sdk:12.11.0-armv7hf-ubuntu24.04 tar \ --create \ --directory /opt/ \ --file - \ @@ -18,7 +18,7 @@ docker run axisecp/acap-native-sdk:12.1.0-armv7hf-ubuntu24.04 tar \ --strip-components 1 # Keep version in sync with `Dockerfile`. -docker run axisecp/acap-native-sdk:12.1.0-aarch64-ubuntu24.04 tar \ +docker run axisecp/acap-native-sdk:12.11.0-aarch64-ubuntu24.04 tar \ --create \ --directory /opt/ \ --file - \ diff --git a/Cargo.lock b/Cargo.lock index a2b2082f..05bf53b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -743,6 +743,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "datahub-sys" +version = "0.0.0" +dependencies = [ + "bindgen 0.69.5", + "libc", + "pkg-config", +] + [[package]] name = "digest" version = "0.10.7" diff --git a/Cargo.toml b/Cargo.toml index a36ea870..24200f3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "apps/*", - "crates/*", + "apps/*", + "crates/*", ] resolver = "2" @@ -60,6 +60,8 @@ bbox = { path = "crates/bbox" } bbox-sys = { path = "crates/bbox-sys" } cargo-acap-build = { path = "crates/cargo-acap-build" } cli-version = { path = "crates/cli-version" } +datahub-sys = { path = "crates/datahub-sys" } +device-manager = { path = "crates/device-manager" } larod-sys = { path = "crates/larod-sys" } licensekey = { path = "crates/licensekey" } licensekey-sys = { path = "crates/licensekey-sys" } diff --git a/crates/datahub-sys/Cargo.toml b/crates/datahub-sys/Cargo.toml new file mode 100644 index 00000000..14d4989d --- /dev/null +++ b/crates/datahub-sys/Cargo.toml @@ -0,0 +1,13 @@ +[package] +build = "build.rs" +name = "datahub-sys" +version = "0.0.0" +edition.workspace = true +license = "MIT" + +[build-dependencies] +bindgen = { workspace = true } +pkg-config = { workspace = true } + +[dependencies] +libc = { workspace = true } diff --git a/crates/datahub-sys/build.rs b/crates/datahub-sys/build.rs new file mode 100644 index 00000000..0a280d99 --- /dev/null +++ b/crates/datahub-sys/build.rs @@ -0,0 +1,29 @@ +use std::{env, path}; + +fn populated_bindings(dst: &path::PathBuf) { + let library = pkg_config::Config::new() + .probe("device-data-hub-client-c") + .unwrap(); + let mut bindings = bindgen::Builder::default() + .header("wrapper.h") + .generate_comments(false) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .allowlist_function("^(dh_.*)$") + .allowlist_type("^(DH.*)$") + .allowlist_var("^(DH_.*)$") + .allowlist_recursively(false) + .layout_tests(false); + for path in library.include_paths { + bindings = bindings.clang_args(&["-I", path.to_str().unwrap()]); + } + bindings.generate().unwrap().write_to_file(dst).unwrap(); +} + +fn main() { + let dst = path::PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs"); + if env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default() != "x86_64" + && env::var("CARGO_CFG_TARGET_OS").unwrap_or_default() != "macos" + { + populated_bindings(&dst); + } +} diff --git a/crates/datahub-sys/src/bindings.rs b/crates/datahub-sys/src/bindings.rs new file mode 100644 index 00000000..10727bdd --- /dev/null +++ b/crates/datahub-sys/src/bindings.rs @@ -0,0 +1,684 @@ +/* automatically generated by rust-bindgen 0.69.5 */ + +#[doc = " @brief API error codes enumeration\n\n Defines all possible error conditions that can occur when using the\n Device Data Hub C Client API."] +pub type DHErrorCode = u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHError_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque error\n\n Represents an error condition with both an error code and descriptive message.\n This structure encapsulates error information with both an error code and message."] +pub type DHError = DHError_t; +extern "C" { + #[doc = " @brief Gets the error message from an error object\n\n Returns a human-readable description of the error condition.\n\n @param err The error object (must not be NULL)\n @return The error message string, or NULL if err is invalid"] + pub fn dh_error_get_message(err: *const DHError) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets the error code from an error object\n\n Returns the specific error code that identifies the type of error.\n\n @param err The error object (must not be NULL)\n @return The error code, or DH_ERR_INVALID_PARAMS if err is invalid"] + pub fn dh_error_get_code(err: *const DHError) -> DHErrorCode; +} +extern "C" { + #[doc = " @brief Converts an error code to its string representation\n\n Returns a human-readable string name for the given error code.\n For example, DH_ERR_INVALID_PARAMS returns \"DH_ERR_INVALID_PARAMS\".\n\n @param code The error code to convert\n @return The error code name as a string, or \"DH_ERR_UNKNOWN_ERROR\" if code is not recognized"] + pub fn dh_error_code_to_string(code: DHErrorCode) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets a string representation of the complete error\n\n Returns a formatted string containing both the error code and message.\n The returned string is owned by the error object and should not be freed.\n\n @param err The error object (must not be NULL)\n @return Formatted error string, or NULL if err is invalid"] + pub fn dh_error_to_string(err: *const DHError) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Destroys an error object\n\n Frees all resources associated with the error object.\n\n @param err The error object to destroy (can be NULL)"] + pub fn dh_error_destroy(err: *mut DHError); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTimestamp_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque UTC timestamp\n\n Represents a point in time with nanosecond precision.\n Use dh_timestamp_get_as_sec() or dh_timestamp_get_as_ms() to retrieve the value."] +pub type DHTimestamp = DHTimestamp_t; +extern "C" { + #[doc = " @brief Creates a timestamp set to the current time\n\n @return New DHTimestamp set to the current UTC time, or NULL on memory allocation failure"] + pub fn dh_timestamp_create() -> *mut DHTimestamp; +} +extern "C" { + #[doc = " @brief Sets the timestamp from a Unix epoch value in seconds\n\n @param timestamp The timestamp to update (must not be NULL)\n @param seconds Seconds since Unix epoch (1970-01-01 00:00:00 UTC)"] + pub fn dh_timestamp_set_with_sec(timestamp: *mut DHTimestamp, seconds: i64); +} +extern "C" { + #[doc = " @brief Sets the timestamp from a Unix epoch value in milliseconds\n\n @param timestamp The timestamp to update (must not be NULL)\n @param milliseconds Milliseconds since Unix epoch (1970-01-01 00:00:00 UTC)"] + pub fn dh_timestamp_set_with_ms(timestamp: *mut DHTimestamp, milliseconds: i64); +} +extern "C" { + #[doc = " @brief Updates the timestamp to the current time\n\n @param timestamp The timestamp to update (must not be NULL)"] + pub fn dh_timestamp_set_current(timestamp: *mut DHTimestamp); +} +extern "C" { + #[doc = " @brief Gets the timestamp value as seconds since Unix epoch\n\n @param timestamp The timestamp (must not be NULL)\n @return Seconds since Unix epoch, or 0 if timestamp is NULL"] + pub fn dh_timestamp_get_as_sec(timestamp: *const DHTimestamp) -> i64; +} +extern "C" { + #[doc = " @brief Gets the timestamp value as milliseconds since Unix epoch\n\n @param timestamp The timestamp (must not be NULL)\n @return Milliseconds since Unix epoch, or 0 if timestamp is NULL"] + pub fn dh_timestamp_get_as_ms(timestamp: *const DHTimestamp) -> i64; +} +extern "C" { + #[doc = " @brief Destroys a timestamp\n\n Frees all resources associated with the DHTimestamp.\n\n @param timestamp The timestamp to destroy (can be NULL)"] + pub fn dh_timestamp_destroy(timestamp: *mut DHTimestamp); +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTopic_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque topic\n\n Represents a topic on the Device Data Hub. Topics are units of information used to\n exchange data between components. Each topic has a definition that describes\n its name, payload structure, QoS settings, etc."] +pub type DHTopic = DHTopic_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTopicData_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque topic data\n\n Represents the structured data content of a topic. The data is stored\n internally as JSON and can be manipulated using the topic_data_* functions."] +pub type DHTopicData = DHTopicData_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHInstanceKeys_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque instance keys\n\n Represents a set of typed key-value pairs that uniquely identify a topic instance.\n Keys can hold either string or integer values"] +pub type DHInstanceKeys = DHInstanceKeys_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTopicInstance_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque topic instance\n\n Represents a specific instance of a topic. Instances are identified by\n a combination of key-value pairs and allow topics to contain multiple\n separate data streams (e.g., multiple detected objects, multiple I/O ports).\n TopicInstance objects represent specific instances of topics identified\n by their keys."] +pub type DHTopicInstance = DHTopicInstance_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTopicSample_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque topic sample\n\n Represents a single data sample within a topic or topic instance.\n Samples contain the actual data along with metadata like timestamps."] +pub type DHTopicSample = DHTopicSample_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTopicList_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque topic list\n\n Contains an array of topic names returned by topic listing operations.\n Must be freed using dh_topic_list_destroy()."] +pub type DHTopicList = DHTopicList_t; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHTopicInstanceList_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque topic instance list\n\n Contains an array of topic instances returned by instance listing operations.\n Must be freed using dh_topic_instance_list_destroy()."] +pub type DHTopicInstanceList = DHTopicInstanceList_t; +extern "C" { + #[doc = " @brief Gets the name of a topic\n\n Returns the topic name as specified in the topic definition.\n\n @param topic The topic (must not be NULL)\n @return The topic name string, or NULL if invalid"] + pub fn dh_topic_get_name(topic: *const DHTopic) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets the topic definition as a JSON string\n\n Returns a reference to the topic definition as a string in JSON format.\n The returned string is owned by the topic object and should not be freed.\n\n @param topic The topic (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return The topic definition JSON string, or NULL on error"] + pub fn dh_topic_get_json_definition( + topic: *const DHTopic, + error: *mut *mut DHError, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Destroys a topic\n\n Frees resources associated with a topic. Does not delete the\n topic from the Device Data Hub, only releases local resources.\n\n @param topic The topic to destroy"] + pub fn dh_topic_destroy(topic: *mut DHTopic); +} +extern "C" { + #[doc = " @brief Creates an empty topic data object\n\n Creates a new DHTopicData with an empty value.\n\n @return New DHTopicData, or NULL on memory allocation failure"] + pub fn dh_topic_data_create() -> *mut DHTopicData; +} +extern "C" { + #[doc = " @brief Destroys a topic data object\n\n Frees all resources associated with the DHTopicData.\n\n @param topic_data The DHTopicData to destroy (can be NULL)"] + pub fn dh_topic_data_destroy(topic_data: *mut DHTopicData); +} +extern "C" { + #[doc = " @brief Sets the value of topic data from JSON string\n\n Parses the JSON string and updates the topic data with the new value.\n\n @param topic_data The DHTopicData (must not be NULL)\n @param json_str JSON string containing the new value (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the input is not valid JSON\n\n **Possible error conditions:**\n - Invalid JSON string (`DH_ERR_INVALID_PARAMS`)"] + pub fn dh_topic_data_set_json_data( + topic_data: *mut DHTopicData, + json_str: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Gets the topic data value as a JSON string\n\n Returns the current topic data value as a JSON-formatted string.\n The returned string is owned by the DHTopicData object and should not be freed.\n\n @param topic_data The DHTopicData (must not be NULL)\n @return JSON string representation, or NULL if invalid"] + pub fn dh_topic_data_get_json_data( + topic_data: *const DHTopicData, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets the topic name from a sample\n\n Returns the name of the topic this sample belongs to.\n The returned string is owned by the DHTopicSample and should not be freed.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The topic name string, or NULL if invalid"] + pub fn dh_topic_sample_get_topic_name( + topic_sample: *const DHTopicSample, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets the sample ID\n\n Returns the unique identifier for this sample within its topic.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The sample ID, or 0 if invalid"] + pub fn dh_topic_sample_get_sample_id(topic_sample: *const DHTopicSample) -> u64; +} +extern "C" { + #[doc = " @brief Checks if the sample is historical data\n\n Returns whether this sample was received as part of cached history\n rather than as a live update.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return true if historical data, false otherwise or if invalid"] + pub fn dh_topic_sample_is_historical(topic_sample: *const DHTopicSample) -> bool; +} +extern "C" { + #[doc = " @brief Gets the source timestamp\n\n Returns the timestamp provided by the producing application when\n the data was written.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The source timestamp, or NULL if invalid.\n The returned pointer is owned by the sample and must not be freed."] + pub fn dh_topic_sample_get_timestamp(topic_sample: *const DHTopicSample) -> *const DHTimestamp; +} +extern "C" { + #[doc = " @brief Gets the topic data from a sample\n\n Returns the topic data contained in this sample.\n The returned pointer is owned by the TopicSample and should not be freed.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The topic data, or NULL if invalid"] + pub fn dh_topic_sample_get_data(topic_sample: *const DHTopicSample) -> *const DHTopicData; +} +extern "C" { + #[doc = " @brief Creates an empty instance keys object\n\n @return New DHInstanceKeys with no keys set, or NULL on memory allocation failure"] + pub fn dh_instance_keys_create() -> *mut DHInstanceKeys; +} +extern "C" { + #[doc = " @brief Destroys an instance keys object\n\n @param keys The DHInstanceKeys to destroy (can be NULL)"] + pub fn dh_instance_keys_destroy(keys: *mut DHInstanceKeys); +} +extern "C" { + #[doc = " @brief Adds a string key-value pair\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param value The string value (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_instance_keys_add_string( + keys: *mut DHInstanceKeys, + name: *const ::std::os::raw::c_char, + value: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Adds an integer key-value pair\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param value The integer value\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_instance_keys_add_integer( + keys: *mut DHInstanceKeys, + name: *const ::std::os::raw::c_char, + value: i64, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Checks whether a key exists\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name to look up (must not be NULL)\n @return true if the key exists, false otherwise"] + pub fn dh_instance_keys_has_key( + keys: *const DHInstanceKeys, + name: *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + #[doc = " @brief Gets the string value of a key\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param out_value Output pointer set to the string value on success (must not be NULL).\n The returned string is owned by the DHInstanceKeys and must not be freed.\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the key does not exist or is not a string"] + pub fn dh_instance_keys_get_string( + keys: *const DHInstanceKeys, + name: *const ::std::os::raw::c_char, + out_value: *mut *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Gets the integer value of a key\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param out_value Output pointer set to the integer value on success (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the key does not exist or is not an integer"] + pub fn dh_instance_keys_get_integer( + keys: *const DHInstanceKeys, + name: *const ::std::os::raw::c_char, + out_value: *mut i64, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Removes a key\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name to remove (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the key does not exist"] + pub fn dh_instance_keys_remove( + keys: *mut DHInstanceKeys, + name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Gets the topic name of an instance\n\n Returns the name of the topic that this instance belongs to.\n\n @param topic_instance The TopicInstance (must not be NULL)\n @return Topic name string, or NULL if invalid"] + pub fn dh_topic_instance_get_topic_name( + topic_instance: *const DHTopicInstance, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets the instance keys\n\n Returns the key-value pairs that identify this specific instance.\n The returned DHInstanceKeys object is owned by the DHTopicInstance and should not be modified\n or freed.\n\n @param topic_instance The TopicInstance (must not be NULL)\n @return DHInstanceKeys object containing keys, or NULL if invalid"] + pub fn dh_topic_instance_get_keys( + topic_instance: *const DHTopicInstance, + ) -> *const DHInstanceKeys; +} +extern "C" { + #[doc = " @brief Gets the instance information\n\n Returns additional information associated with this instance, if any.\n The returned string is owned by the DHTopicInstance and should not be modified or\n freed.\n\n @param topic_instance The DHTopicInstance (must not be NULL)\n @return The instance info string, or NULL if no info or invalid"] + pub fn dh_topic_instance_get_info( + topic_instance: *const DHTopicInstance, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Destroys a topic instance\n\n Frees all resources associated with the DHTopicInstance.\n\n @param topic_instance The DHTopicInstance to destroy (can be NULL)"] + pub fn dh_topic_instance_destroy(topic_instance: *mut DHTopicInstance); +} +extern "C" { + #[doc = " @brief Gets the number of topics in the list\n\n @param list The DHTopicList (must not be NULL)\n @return The number of topics, or 0 if invalid"] + pub fn dh_topic_list_get_count(list: *const DHTopicList) -> u32; +} +extern "C" { + #[doc = " @brief Gets a topic name by index\n\n Returns the topic name at the specified index.\n The returned string is owned by the DHTopicList and should not be freed.\n\n @param list The DHTopicList (must not be NULL)\n @param index Zero-based index into the list. Must be less than the value returned by\n dh_topic_list_get_count()\n @return The topic name string, or NULL if invalid or out of bounds"] + pub fn dh_topic_list_get_name( + list: *const DHTopicList, + index: u32, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Frees a topic list\n\n Releases memory allocated for a topic list returned by dh_client_get_topic_list().\n\n @param topic_list The topic list to free (can be NULL)"] + pub fn dh_topic_list_destroy(topic_list: *mut DHTopicList); +} +extern "C" { + #[doc = " @brief Gets the number of instances in the list\n\n @param list The DHTopicInstanceList (must not be NULL)\n @return The number of instances, or 0 if invalid"] + pub fn dh_topic_instance_list_get_count(list: *const DHTopicInstanceList) -> u32; +} +extern "C" { + #[doc = " @brief Gets a topic instance by index\n\n Returns the topic instance at the specified index.\n The returned pointer is owned by the DHTopicInstanceList and should not be freed.\n\n @param list The DHTopicInstanceList (must not be NULL)\n @param index Zero-based index into the list. Must be less than the value returned by\n dh_topic_instance_list_get_count()\n @return The topic instance, or NULL if invalid or out of bounds"] + pub fn dh_topic_instance_list_get( + list: *const DHTopicInstanceList, + index: u32, + ) -> *const DHTopicInstance; +} +extern "C" { + #[doc = " @brief Frees a topic instance list\n\n Releases memory allocated for an instance list returned by\n dh_client_get_topic_instances().\n\n @param instance_list The instance list to free (can be NULL)"] + pub fn dh_topic_instance_list_destroy(instance_list: *mut DHTopicInstanceList); +} +#[doc = " @brief Consumer match status enumeration\n\n Indicates whether there are consumers interested in the data being produced.\n Used for consumer-producer matching to optimize resource usage."] +pub type DHConsumerMatchStatus = u32; +#[doc = " @brief Production identifier type\n\n Unique identifier for a production registration. Used to track and manage\n producer-consumer matching registrations."] +pub type DHProductionId = u64; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHWriter_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque writer handle\n\n Publishes data to a topic, handling both instanced and non-instanced topics\n with automatic instance management."] +pub type DHWriter = DHWriter_t; +#[doc = " @brief Consumer match update callback function type for DHWriter\n\n Called when the consumer match status changes for a registered production.\n This allows applications to start/stop data production based on consumer interest.\n\n @param production_id Production ID that this update relates to\n @param status New consumer match status"] +pub type DHOnConsumerMatchUpdateCallback = ::std::option::Option< + unsafe extern "C" fn( + production_id: DHProductionId, + status: DHConsumerMatchStatus, + user_data: *mut ::std::os::raw::c_void, + ), +>; +extern "C" { + #[doc = " @brief Destroys a writer\n\n Automatically cleans up any registered productions and frees all resources\n associated with the writer. Active instances may be deleted based\n on their configuration.\n\n @param writer The writer to destroy (can be NULL)"] + pub fn dh_writer_destroy(writer: *mut DHWriter); +} +extern "C" { + #[doc = " @brief Sets the consumer match update callback\n\n Registers a callback to be invoked when the consumer match status changes\n for any registered production. Pass NULL to remove the callback.\n\n @param writer The writer (must not be NULL)\n @param callback Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)"] + pub fn dh_writer_set_consumer_match_update_callback( + writer: *mut DHWriter, + callback: DHOnConsumerMatchUpdateCallback, + user_data: *mut ::std::os::raw::c_void, + ); +} +extern "C" { + #[doc = " @brief Gets the name of a writer\n\n Returns the name that was specified when the writer was created.\n\n @param writer The writer (must not be NULL)\n @return The writer name, or NULL if invalid"] + pub fn dh_writer_get_name(writer: *const DHWriter) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Gets the topic name this writer is initialized for\n\n Returns the name of the topic that was specified when the writer was\n created with dh_client_create_writer().\n The returned string is owned by the writer and must not be freed.\n\n @param writer The writer (must not be NULL)\n @return The topic name, or NULL if invalid"] + pub fn dh_writer_get_topic_name(writer: *const DHWriter) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Writes data to the topic\n\n Writes the given data to the associated topic.\n\n If the topic is defined to have instances, the data will be written to\n the corresponding instance. If the instance doesn't exist it must be\n created first.\n\n If the topic doesn't support instances the data will be written to the\n default instance.\n\n If the sample number has reached the limit the oldest sample will be removed\n before adding the new sample.\n\n @param writer The writer (must not be NULL)\n @param instance_keys The instance keys identifying the target instance (can be NULL for topics without instances)\n @param topic_data The data to write (must not be NULL)\n @param timestamp Optional source timestamp (can be NULL for automatic timestamp)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_INSTANCE`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_INVALID_DATA`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_writer_write_data( + writer: *mut DHWriter, + instance_keys: *const DHInstanceKeys, + topic_data: *const DHTopicData, + timestamp: *const DHTimestamp, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Creates a topic instance explicitly\n\n Creates a new instance for the topic identified by the given key-value pairs.\n This is useful for pre-creating instances or when you need explicit control\n over instance lifecycle.\n\n @param writer The writer (must not be NULL)\n @param instance_keys Key-value pairs that uniquely identify the instance (must not be NULL)\n @param instance_info Optional string with additional instance information (can be NULL)\n @param delete_on_disconnect If true, the instance will be deleted when the client disconnects\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_KEYS`\n - `DH_ERR_INSTANCES_NOT_SUPPORTED`\n - `DH_ERR_INSTANCE_EXISTS`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_MAX_INSTANCES`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_writer_create_instance( + writer: *mut DHWriter, + instance_keys: *const DHInstanceKeys, + instance_info: *const ::std::os::raw::c_char, + delete_on_disconnect: bool, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Deletes a specific topic instance\n\n Removes the instance identified by the given key-value pairs and all its\n samples from the topic.\n\n @param writer The writer (must not be NULL)\n @param instance_keys Key-value pairs identifying the instance to delete (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_KEYS`\n - `DH_ERR_INSTANCES_NOT_SUPPORTED`\n - `DH_ERR_INVALID_INSTANCE`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_writer_delete_instance( + writer: *mut DHWriter, + instance_keys: *const DHInstanceKeys, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Deletes all instances of the topic\n\n Removes all instances and their samples from the topic. Use with caution\n as this affects all data in the topic.\n\n @param writer The writer (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_KEYS`\n - `DH_ERR_INSTANCES_NOT_SUPPORTED`\n - `DH_ERR_INVALID_INSTANCE`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_writer_delete_all_instances(writer: *mut DHWriter, error: *mut *mut DHError) -> bool; +} +extern "C" { + #[doc = " @brief Registers production intent for consumer matching\n\n Registers the instance keys identifying the data this writer intends to produce.\n This enables consumer-producer matching, allowing the application to receive\n notifications when consumers are interested in this type of data. This is useful\n for optimizing resource usage by avoiding unnecessary data production.\n\n The application will be notified via the callback set with\n dh_writer_set_consumer_match_update_callback() when consumers show interest in\n or lose interest in the registered data.\n\n @param writer The writer (must not be NULL)\n @param instance_keys Key-value pairs identifying the instance to register production for\n (can be NULL). If NULL, all instances will be considered as matching.\n @param production_id Output parameter for the production ID (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_MAX_PRODUCTIONS`\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_writer_register_production( + writer: *mut DHWriter, + instance_keys: *const DHInstanceKeys, + production_id: *mut DHProductionId, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Unregisters a production registration\n\n Removes a previously registered production. No further consumer match\n notifications will be received for this production ID.\n\n @param writer The writer (must not be NULL)\n @param production_id The production ID to unregister\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_PRODUCTION`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_writer_unregister_production( + writer: *mut DHWriter, + production_id: DHProductionId, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Gets the current consumer match status for a production\n\n Checks whether there are currently consumers interested in the data\n associated with the specified production registration.\n\n @param writer The writer (must not be NULL)\n @param production_id The production ID to check\n @param status Output parameter for the consumer match status (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_INVALID_PRODUCTION`"] + pub fn dh_writer_get_consumer_match_status( + writer: *mut DHWriter, + production_id: DHProductionId, + status: *mut DHConsumerMatchStatus, + error: *mut *mut DHError, + ) -> bool; +} +#[doc = " @brief Topic update type enumeration\n\n Indicates whether a topic was created or deleted.\n Used in topic update callbacks."] +pub type DHTopicUpdateType = u32; +#[doc = " @brief Topic instance update type enumeration\n\n Indicates whether a topic instance was created or deleted.\n Used in topic instance update callbacks."] +pub type DHTopicInstanceUpdateType = u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHSubscriber_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque subscriber handle\n\n Represents a subscriber for receiving data from one or more topics simultaneously."] +pub type DHSubscriber = DHSubscriber_t; +#[doc = " @brief Topic update callback function type\n\n Called when a topic matching the subscription filters is created or deleted.\n\n @param topic_name Name of the topic that was updated (must not be NULL)\n @param update_type Whether the topic was created or deleted\n @param user_data User-provided context pointer"] +pub type DHOnTopicUpdateCallback = ::std::option::Option< + unsafe extern "C" fn( + topic_name: *const ::std::os::raw::c_char, + update_type: DHTopicUpdateType, + user_data: *mut ::std::os::raw::c_void, + ), +>; +#[doc = " @brief Instance update callback function type\n\n Called when a topic instance matching the subscription filters is created or deleted.\n\n @param topic_instance The topic instance that was updated (must not be NULL)\n @param update_type Whether the instance was created or deleted\n @param user_data User-provided context pointer"] +pub type DHOnInstanceUpdateCallback = ::std::option::Option< + unsafe extern "C" fn( + topic_instance: *const DHTopicInstance, + update_type: DHTopicInstanceUpdateType, + user_data: *mut ::std::os::raw::c_void, + ), +>; +#[doc = " @brief Data update callback function type\n\n Called when new data matching the subscription filters is received.\n This is the primary callback for receiving topic data.\n\n @param topic_sample The received topic sample (must not be NULL)\n @param user_data User-provided context pointer"] +pub type DHOnDataCallback = ::std::option::Option< + unsafe extern "C" fn( + topic_sample: *const DHTopicSample, + user_data: *mut ::std::os::raw::c_void, + ), +>; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHFilter_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque subscription filter\n\n Represents a single filter used to match incoming samples. A filter carries\n three independent criteria — topic names, instance key sets, and data\n expressions — that are each logically OR-ed within the filter:\n a sample passes if its topic name matches **any** added topic name,\n its instance matches **any** added instance key set, or its data satisfies\n **any** added data expression.\n\n Create with dh_filter_create() and destroy with dh_filter_destroy()."] +pub type DHFilter = DHFilter_t; +extern "C" { + #[doc = " @brief Creates an empty filter\n\n @return New DHFilter with no criteria set, or NULL on memory allocation failure"] + pub fn dh_filter_create() -> *mut DHFilter; +} +extern "C" { + #[doc = " @brief Destroys a filter\n\n Frees all resources associated with the filter.\n\n @param filter The filter to destroy (can be NULL)"] + pub fn dh_filter_destroy(filter: *mut DHFilter); +} +extern "C" { + #[doc = " @brief Adds a topic name to the filter. A sample matches if its topic name matches any of the\n added topic names (logical OR).\n @param filter The filter to modify (must not be NULL)\n @param topic_name The topic name to add (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_filter_add_topic_name( + filter: *mut DHFilter, + topic_name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Adds an instance key filter. A sample matches if it matches any of the added instance key\n filters (logical OR). Each instance key filter can contain multiple key-value pairs that must\n all match (logical AND).\n @param filter The filter to modify (must not be NULL)\n @param instance_keys The instance keys to add as a filter (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_filter_add_instance( + filter: *mut DHFilter, + instance_keys: *const DHInstanceKeys, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Adds a data expression to the filter. A sample matches if it matches any of the data\n expressions. The data expression is an expression string applied to each incoming sample to\n filter based on sample data content. Multiple expressions are logically OR-ed: a sample passes\n if it satisfies **any** of the added expressions. The expression is a limited subset of\n operators. The following operators are supported: `()`, `==`, `!=`, `>`, `>=`, `<=`, `<`,\n `and`, `or`, `not`, `has()`. Data fields can be accessed using `.` notation,\n e.g. `.field.subfield`.\n @param filter The filter to modify (must not be NULL)\n @param data_expression The data expression (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_filter_add_data_expression( + filter: *mut DHFilter, + data_expression: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +pub type DHStartFrom = u32; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHSubscribeOptions_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque subscription options\n\n Aggregates one or more DHFilter objects and update-enable flags into a\n single configuration passed to a subscribe call.\n Multiple filters are logically OR-ed: a sample matches if **any** filter\n matches.\n\n Create with dh_subscribe_options_create() and destroy with\n dh_subscribe_options_destroy()."] +pub type DHSubscribeOptions = DHSubscribeOptions_t; +extern "C" { + #[doc = " @brief Creates a subscription options object with default settings\n\n Default: no filters, all update types disabled, start from now.\n\n @return New DHSubscribeOptions, or NULL on memory allocation failure"] + pub fn dh_subscribe_options_create() -> *mut DHSubscribeOptions; +} +extern "C" { + #[doc = " @brief Destroys a subscription options object\n\n @param options The options to destroy (can be NULL)"] + pub fn dh_subscribe_options_destroy(options: *mut DHSubscribeOptions); +} +extern "C" { + #[doc = " @brief Adds a filter to the subscription options. Each filter is evaluated independently\n and matches if any filter matches (logical OR).\n @param options The subscription options (must not be NULL)\n @param filter The filter to add (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_subscribe_options_add_filter( + options: *mut DHSubscribeOptions, + filter: *const DHFilter, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Enables or disables topic creation/deletion notifications\n\n @param options The options to modify (must not be NULL)\n @param enable true to enable, false to disable"] + pub fn dh_subscribe_options_set_enable_topic_updates( + options: *mut DHSubscribeOptions, + enable: bool, + ); +} +extern "C" { + #[doc = " @brief Enables or disables instance creation/deletion notifications\n\n @param options The options to modify (must not be NULL)\n @param enable true to enable, false to disable"] + pub fn dh_subscribe_options_set_enable_instance_updates( + options: *mut DHSubscribeOptions, + enable: bool, + ); +} +extern "C" { + #[doc = " @brief Enables or disables data update notifications\n\n @param options The options to modify (must not be NULL)\n @param enable true to enable, false to disable"] + pub fn dh_subscribe_options_set_enable_data_updates( + options: *mut DHSubscribeOptions, + enable: bool, + ); +} +extern "C" { + #[doc = " @brief Sets the starting point for data delivery\n\n @param options The options to modify (must not be NULL)\n @param start_from DH_START_FROM_NOW or DH_START_FROM_OLDEST"] + pub fn dh_subscribe_options_set_start_from( + options: *mut DHSubscribeOptions, + start_from: DHStartFrom, + ); +} +extern "C" { + #[doc = " @brief Destroys a subscriber\n\n Automatically unsubscribes if still subscribed and frees all resources\n associated with the subscriber.\n\n @param subscriber The subscriber to destroy (can be NULL)"] + pub fn dh_subscriber_destroy(subscriber: *mut DHSubscriber); +} +extern "C" { + #[doc = " @brief Gets the name of a subscriber\n\n Returns the name that was specified when the subscriber was created.\n\n @param subscriber The subscriber (must not be NULL)\n @return The subscriber name, or NULL if invalid"] + pub fn dh_subscriber_get_name(subscriber: *const DHSubscriber) + -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Sets the topic update callback\n\n Registers a callback to be invoked when a topic matching the subscription\n is created or deleted. Pass NULL to remove the callback.\n\n @param subscriber The subscriber (must not be NULL)\n @param on_topic_update Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_subscriber_set_topic_update_callback( + subscriber: *mut DHSubscriber, + on_topic_update: DHOnTopicUpdateCallback, + user_data: *mut ::std::os::raw::c_void, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Sets the instance update callback\n\n Registers a callback to be invoked when a topic instance matching the\n subscription is created or deleted. Pass NULL to remove the callback.\n\n @param subscriber The subscriber (must not be NULL)\n @param on_instance_update Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_subscriber_set_instance_update_callback( + subscriber: *mut DHSubscriber, + on_instance_update: DHOnInstanceUpdateCallback, + user_data: *mut ::std::os::raw::c_void, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Sets the data callback\n\n Registers a callback to be invoked when a data sample matching the\n subscription is received. Pass NULL to remove the callback.\n\n @param subscriber The subscriber (must not be NULL)\n @param on_data Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_subscriber_set_data_callback( + subscriber: *mut DHSubscriber, + on_data: DHOnDataCallback, + user_data: *mut ::std::os::raw::c_void, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Subscribes to one or more topics with optional instance and data filtering\n\n Establishes a subscription to receive data from one or more topics,\n with optional filtering by instance keys and/or a data filter expression.\n\n @param subscriber The subscriber (must not be NULL)\n @param options Subscription options specifying filters and update types (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_DATA`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_MAX_SUBSCRIPTIONS`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_subscriber_subscribe( + subscriber: *mut DHSubscriber, + options: *const DHSubscribeOptions, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Unsubscribes from all topics\n\n Terminates all active subscriptions for this subscriber.\n No further callbacks will be received after this call completes successfully.\n\n @param subscriber The subscriber (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_SUBSCRIPTION`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_subscriber_unsubscribe( + subscriber: *mut DHSubscriber, + error: *mut *mut DHError, + ) -> bool; +} +#[doc = " @brief Enumeration of connection states for the Device Data Hub client.\n\n Represents the various states that the client's connection to the Device Data Hub\n can be in, such as disconnected, connected, or in the process of connecting."] +pub type DHConnectionState = u32; +#[doc = " @brief Enumeration of available log levels for the Device Data Hub client.\n\n Defines the severity levels for logging messages, ordered from least verbose (OFF)\n to most verbose (DH_LOG_TRACE). Each level includes all messages from less verbose levels."] +pub type DHLogLevel = u32; +#[doc = " @brief Enumeration of available log output targets.\n\n Specifies where log messages should be directed."] +pub type DHLogTarget = u32; +#[doc = " @brief Connection state update callback function type\n\n Callback function called when the connection state changes.\n\n @param update The new connection state\n @param user_data User-provided data passed to dh_client_set_connection_update_callback()"] +pub type DHOnConnectionUpdateCallback = ::std::option::Option< + unsafe extern "C" fn(update: DHConnectionState, user_data: *mut ::std::os::raw::c_void), +>; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct DHClient_t { + _unused: [u8; 0], +} +#[doc = " @brief Opaque client handle"] +pub type DHClient = DHClient_t; +extern "C" { + #[doc = " @brief Creates a new client instance\n\n Creates a new Device Data Hub client with the specified name.\n\n @param name The name of the client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the newly created client, or NULL on failure"] + pub fn dh_client_create( + name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHClient; +} +extern "C" { + #[doc = " @brief Gets the name of the client\n\n Returns the name that was specified when the client was created.\n\n @param client The client (must not be NULL)\n @return The client name as a string, or NULL if client is invalid"] + pub fn dh_client_get_name(client: *const DHClient) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " @brief Sets the connection state update callback\n\n Registers a callback to receive connection state change notifications.\n\n @param client The client (must not be NULL)\n @param callback Callback function for connection state changes (can be NULL to remove)\n @param user_data User-provided data passed to the callback (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_client_set_connection_update_callback( + client: *mut DHClient, + callback: DHOnConnectionUpdateCallback, + user_data: *mut ::std::os::raw::c_void, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Connects the client synchronously to the Device Data Hub.\n\n This function attempts to establish a connection between the client and the\n Device Data Hub. The client must have the required access rights to connect.\n Once connected, the client can perform operations such as publishing data to\n and subscribing to topics on the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_ALREADY_CONNECTED`\n - `DH_ERR_CREDENTIAL_ERROR`\n - `DH_ERR_AUTHENTICATION_FAILED`\n - `DH_ERR_MAX_CLIENTS`\n - `DH_ERR_MAX_CONNECTIONS`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_connect(client: *mut DHClient, error: *mut *mut DHError) -> bool; +} +extern "C" { + #[doc = " @brief Disconnects the client from the Device Data Hub\n\n This method terminates the connection between the client and the Device Data Hub.\n All created writers/subscriptions will be invalidated and won't operate.\n\n @param client The client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_disconnect(client: *mut DHClient, error: *mut *mut DHError) -> bool; +} +extern "C" { + #[doc = " @brief Destroys a client instance\n\n Frees all resources associated with the client. The client will be\n automatically disconnected if still connected.\n This function will block until all ongoing callbacks have completed and no further callbacks will\n be invoked after it returns.\n\n @param client The client to destroy (can be NULL)"] + pub fn dh_client_destroy(client: *mut DHClient); +} +extern "C" { + #[doc = " @brief Gets the current connection state\n\n Returns the detailed connection state of the client.\n\n @param client The client (must not be NULL)\n @return The current connection state"] + pub fn dh_client_get_connection_state(client: *const DHClient) -> DHConnectionState; +} +extern "C" { + #[doc = " @brief Creates a new topic from the definition\n\n Creates a new topic on the Device Data Hub using a topic definition string.\n The format of the definition follows the JSON schema described in\n the main documentation.\n\n @param client The client (must not be NULL)\n @param file_path Path to a JSON file containing the topic definition (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created topic (caller must free with dh_topic_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_TOPIC_EXISTS`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_MAX_TOPIC`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_create_topic_from_file( + client: *mut DHClient, + file_path: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHTopic; +} +extern "C" { + #[doc = " @brief Creates a new topic from the definition\n\n Creates a new topic on the Device Data Hub using a topic definition string.\n The format of the definition follows the JSON schema described in\n the main documentation.\n\n @param client The client (must not be NULL)\n @param topic_def Topic definition in json string (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created topic (caller must free with dh_topic_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_TOPIC_EXISTS`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_MAX_TOPIC`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_create_topic( + client: *mut DHClient, + topic_def: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHTopic; +} +extern "C" { + #[doc = " @brief Deletes a topic from the Device Data Hub\n\n Permanently removes a topic and all its data from the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param topic_name The name of the topic to delete (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_delete_topic( + client: *mut DHClient, + topic_name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> bool; +} +extern "C" { + #[doc = " @brief Gets a list of available topics\n\n Retrieves a list of all topic names available on the Device Data Hub.\n The returned list must be freed using dh_topic_list_destroy().\n\n @param client The client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the topic list (caller must free with dh_topic_list_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_get_topic_list( + client: *mut DHClient, + error: *mut *mut DHError, + ) -> *mut DHTopicList; +} +extern "C" { + #[doc = " @brief Gets a topic by name\n\n Retrieves a topic for an existing topic on the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param topic_name The name of the topic to retrieve (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the topic (caller must free with dh_topic_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_get_topic( + client: *mut DHClient, + topic_name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHTopic; +} +extern "C" { + #[doc = " @brief Gets topic instances for a topic\n\n Retrieves a list of all instances for the specified topic.\n The returned list must be freed using dh_topic_instance_list_destroy().\n\n @param client The client (must not be NULL)\n @param topic_name The name of the topic (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the instance list (caller must free with\n dh_topic_instance_list_destroy()), or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_get_topic_instances( + client: *mut DHClient, + topic_name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHTopicInstanceList; +} +extern "C" { + #[doc = " @brief Creates a writer for a specific topic\n\n Creates a new writer and initializes it for the specified topic.\n The topic must already exist on the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param writer_name The name of the writer (must not be NULL)\n @param topic_name The name of the topic to write to (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created writer (caller must free with dh_writer_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_create_writer( + client: *mut DHClient, + writer_name: *const ::std::os::raw::c_char, + topic_name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHWriter; +} +extern "C" { + #[doc = " @brief Creates a topic data subscriber\n\n Creates a new data subscriber that can receive data from multiple topics.\n\n @param client The client (must not be NULL)\n @param subscriber_name The name of the topic subscriber (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created topic subscriber (caller must free with\n dh_subscriber_destroy()), or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INTERNAL_ERROR`"] + pub fn dh_client_create_subscriber( + client: *mut DHClient, + subscriber_name: *const ::std::os::raw::c_char, + error: *mut *mut DHError, + ) -> *mut DHSubscriber; +} +extern "C" { + #[doc = " @brief Configures logging for the Device Data Hub client\n\n This method allows dynamic configuration of the logging settings\n for the Device Data Hub client at runtime.\n\n @param client The client (must not be NULL)\n @param level The log level to set\n @param target The log output target to set\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] + pub fn dh_client_set_logging( + client: *mut DHClient, + level: DHLogLevel, + target: DHLogTarget, + error: *mut *mut DHError, + ) -> bool; +} diff --git a/crates/datahub-sys/src/lib.rs b/crates/datahub-sys/src/lib.rs new file mode 100644 index 00000000..d9f6f6ea --- /dev/null +++ b/crates/datahub-sys/src/lib.rs @@ -0,0 +1,69 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(improper_ctypes)] + +#[cfg(not(target_arch = "x86_64"))] +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); + +#[cfg(target_arch = "x86_64")] +include!("./bindings.rs"); + +// The C headers define the constants below as object-like macros with casts, e.g. +// `#define DH_ERR_INVALID_PARAMS ((DHErrorCode)0)`, which bindgen cannot evaluate, +// so they are transcribed manually. + +pub const DH_ERR_INVALID_PARAMS: DHErrorCode = 0; +pub const DH_ERROR_DATA_TOO_BIG: DHErrorCode = 1; +pub const DH_ERR_NOT_CONNECTED: DHErrorCode = 2; +pub const DH_ERR_ALREADY_CONNECTED: DHErrorCode = 3; +pub const DH_ERR_UNKNOWN_ERROR: DHErrorCode = 4; +pub const DH_ERR_INTERNAL_ERROR: DHErrorCode = 5; +pub const DH_ERR_INVALID_ID: DHErrorCode = 6; +pub const DH_ERR_INVALID_TOPIC: DHErrorCode = 7; +pub const DH_ERR_NOT_INITIALIZED: DHErrorCode = 8; +pub const DH_ERR_MAX_CLIENTS: DHErrorCode = 9; +pub const DH_ERR_MAX_CONNECTIONS: DHErrorCode = 10; +pub const DH_ERR_AUTHENTICATION_FAILED: DHErrorCode = 11; +pub const DH_ERR_TOPIC_EXISTS: DHErrorCode = 12; +pub const DH_ERR_MAX_TOPIC: DHErrorCode = 13; +pub const DH_ERR_CONNECTION_ERROR: DHErrorCode = 14; +pub const DH_ERR_INVALID_DATA: DHErrorCode = 15; +pub const DH_ERR_INVALID_INSTANCE: DHErrorCode = 16; +pub const DH_ERR_INVALID_KEYS: DHErrorCode = 17; +pub const DH_ERR_INVALID_SUBSCRIPTION: DHErrorCode = 18; +pub const DH_ERR_INSTANCE_EXISTS: DHErrorCode = 19; +pub const DH_ERR_INSTANCES_NOT_SUPPORTED: DHErrorCode = 20; +pub const DH_ERR_MAX_INSTANCES: DHErrorCode = 21; +pub const DH_ERR_MAX_SUBSCRIPTIONS: DHErrorCode = 22; +pub const DH_ERR_AUTHORIZATION_FAILED: DHErrorCode = 23; +pub const DH_ERR_MAX_PRODUCTIONS: DHErrorCode = 24; +pub const DH_ERR_INVALID_PRODUCTION: DHErrorCode = 25; +pub const DH_ERR_INVALID_REQUEST: DHErrorCode = 26; +pub const DH_ERR_CREDENTIAL_ERROR: DHErrorCode = 27; + +pub const DH_CONN_DISCONNECTED: DHConnectionState = 0; +pub const DH_CONN_CONNECTED: DHConnectionState = 1; + +pub const DH_LOG_OFF: DHLogLevel = 0; +pub const DH_LOG_CRITICAL: DHLogLevel = 1; +pub const DH_LOG_ERROR: DHLogLevel = 2; +pub const DH_LOG_WARNING: DHLogLevel = 3; +pub const DH_LOG_INFO: DHLogLevel = 4; +pub const DH_LOG_DEBUG: DHLogLevel = 5; +pub const DH_LOG_TRACE: DHLogLevel = 6; + +pub const DH_LOG_TARGET_CONSOLE: DHLogTarget = 0; +pub const DH_LOG_TARGET_SYSLOG: DHLogTarget = 1; + +pub const DH_TOPIC_CREATED: DHTopicUpdateType = 0; +pub const DH_TOPIC_DELETED: DHTopicUpdateType = 1; + +pub const DH_TOPIC_INSTANCE_CREATED: DHTopicInstanceUpdateType = 0; +pub const DH_TOPIC_INSTANCE_DELETED: DHTopicInstanceUpdateType = 1; + +pub const DH_START_FROM_NOW: DHStartFrom = 0; +pub const DH_START_FROM_OLDEST: DHStartFrom = 1; + +pub const DH_CONSUMER_NO_MATCH: DHConsumerMatchStatus = 0; +pub const DH_CONSUMER_MATCH: DHConsumerMatchStatus = 1; diff --git a/crates/datahub-sys/wrapper.h b/crates/datahub-sys/wrapper.h new file mode 100644 index 00000000..90eb8c54 --- /dev/null +++ b/crates/datahub-sys/wrapper.h @@ -0,0 +1,4 @@ +#include +#include +#include +#include From ee42f41c240cb08aa89f07c977770ce912e57571 Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Tue, 4 Aug 2026 06:37:59 +0200 Subject: [PATCH 2/7] align bindings with existing --- crates/datahub-sys/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/datahub-sys/src/lib.rs b/crates/datahub-sys/src/lib.rs index d9f6f6ea..a23d8599 100644 --- a/crates/datahub-sys/src/lib.rs +++ b/crates/datahub-sys/src/lib.rs @@ -3,10 +3,10 @@ #![allow(non_snake_case)] #![allow(improper_ctypes)] -#[cfg(not(target_arch = "x86_64"))] +#[cfg(not(any(target_arch = "x86_64", target_os = "macos")))] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); -#[cfg(target_arch = "x86_64")] +#[cfg(any(target_arch = "x86_64", target_os = "macos"))] include!("./bindings.rs"); // The C headers define the constants below as object-like macros with casts, e.g. From fed7f386084910c15a52bc00b5d0d1111b7c8574 Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Tue, 4 Aug 2026 06:38:23 +0200 Subject: [PATCH 3/7] s: add example to trigger bindings gen --- Cargo.lock | 10 ++ apps/object_consumer/Cargo.toml | 15 +++ apps/object_consumer/manifest.json | 16 +++ apps/object_consumer/src/main.rs | 200 +++++++++++++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 apps/object_consumer/Cargo.toml create mode 100644 apps/object_consumer/manifest.json create mode 100644 apps/object_consumer/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 05bf53b6..00cfd7b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1842,6 +1842,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "object_consumer" +version = "0.0.0" +dependencies = [ + "acap-logging", + "datahub-sys", + "libc", + "log", +] + [[package]] name = "object_detection" version = "0.0.0" diff --git a/apps/object_consumer/Cargo.toml b/apps/object_consumer/Cargo.toml new file mode 100644 index 00000000..d927ec26 --- /dev/null +++ b/apps/object_consumer/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "object_consumer" +version = "0.0.0" +edition.workspace = true +publish = false + +[dependencies] +libc = { workspace = true } +log = { workspace = true } + +acap-logging = { workspace = true } +datahub-sys = { workspace = true } + +[features] +default = ["acap-logging/default"] diff --git a/apps/object_consumer/manifest.json b/apps/object_consumer/manifest.json new file mode 100644 index 00000000..7c6569ca --- /dev/null +++ b/apps/object_consumer/manifest.json @@ -0,0 +1,16 @@ +{ + "schemaVersion": "2.2.0", + "acapPackageConf": { + "setup": { + "appName": "object_consumer", + "vendor": "Axis Communications", + "runMode": "never", + "version": "0.0.0" + } + }, + "resources": { + "deviceDataHub": { + "enabled": true + } + } +} diff --git a/apps/object_consumer/src/main.rs b/apps/object_consumer/src/main.rs new file mode 100644 index 00000000..616bc2c8 --- /dev/null +++ b/apps/object_consumer/src/main.rs @@ -0,0 +1,200 @@ +//! An example app that subscribes to object detection data using [`datahub_sys`]. +//! +//! Re-implements the [C example for consuming Device Data Hub data]. +//! Unlike the C example, which relies on globals and `atexit`, resources are owned by `main` and +//! released explicitly on every exit path. +//! +//! [C example for consuming Device Data Hub data]: https://github.com/AxisCommunications/acap-native-sdk-examples/tree/main/device-data-hub/acap-communication/object-consumer + +use std::{ + ffi::{c_char, c_int, c_void, CStr}, + process::ExitCode, + ptr, + sync::atomic::{AtomicBool, Ordering}, +}; + +use datahub_sys::{ + dh_client_connect, dh_client_create, dh_client_create_subscriber, dh_client_destroy, + dh_client_disconnect, dh_client_set_logging, dh_error_destroy, dh_error_to_string, + dh_filter_add_topic_name, dh_filter_create, dh_filter_destroy, dh_subscribe_options_add_filter, + dh_subscribe_options_create, dh_subscribe_options_destroy, + dh_subscribe_options_set_enable_data_updates, dh_subscriber_destroy, + dh_subscriber_set_data_callback, dh_subscriber_subscribe, dh_topic_data_get_json_data, + dh_topic_sample_get_data, DHClient, DHError, DHSubscriber, DHTopicSample, DH_LOG_INFO, + DH_LOG_TARGET_CONSOLE, +}; +use libc::{SIGINT, SIGTERM}; +use log::{error, info}; + +const TOPIC_NAME: &CStr = c"com.example.objectdetector"; +const USER_DATA: &CStr = c"object_consumer_data"; + +static KEEP_RUNNING: AtomicBool = AtomicBool::new(true); + +/// Logs and destroys `error`, returning `true`, if it is set; returns `false` otherwise. +unsafe fn handle_client_error(error: *mut DHError, context: &str) -> bool { + if error.is_null() { + return false; + } + let message = CStr::from_ptr(dh_error_to_string(error)).to_string_lossy(); + error!("Error in {context}: {message}"); + let () = dh_error_destroy(error); + true +} + +/// Creates a client and connects it to the Device Data Hub. +unsafe fn initialize_client() -> Option<*mut DHClient> { + let mut error: *mut DHError = ptr::null_mut(); + let client = dh_client_create(c"Client for object_consumer".as_ptr(), &mut error); + if client.is_null() { + let _ = handle_client_error(error, "create client"); + return None; + } + + let mut error: *mut DHError = ptr::null_mut(); + if !dh_client_set_logging(client, DH_LOG_INFO, DH_LOG_TARGET_CONSOLE, &mut error) { + let _ = handle_client_error(error, "set logging"); + } + + let mut error: *mut DHError = ptr::null_mut(); + let _ = dh_client_connect(client, &mut error); + if handle_client_error(error, "client connect") { + let () = dh_client_destroy(client); + return None; + } + + Some(client) +} + +/// Logs the data of each received sample. +unsafe extern "C" fn on_data_received(sample: *const DHTopicSample, user_data: *mut c_void) { + debug_assert!(!sample.is_null()); + debug_assert!(!user_data.is_null()); + let user_data = CStr::from_ptr(user_data.cast::()).to_string_lossy(); + info!("User data: {user_data}"); + let topic_data = dh_topic_sample_get_data(sample); + let data = dh_topic_data_get_json_data(topic_data); + if !data.is_null() { + let data = CStr::from_ptr(data).to_string_lossy(); + info!("Received Object Detection data: {data}"); + } +} + +/// Creates a subscriber and subscribes to data updates for `topics`. +unsafe fn setup_subscription(client: *mut DHClient, topics: &[&CStr]) -> Option<*mut DHSubscriber> { + debug_assert!(!client.is_null()); + let mut error: *mut DHError = ptr::null_mut(); + let subscriber = dh_client_create_subscriber( + client, + c"Data subscriber for object-consumer".as_ptr(), + &mut error, + ); + if handle_client_error(error, "create subscriber") { + return None; + } + + let mut error: *mut DHError = ptr::null_mut(); + let _ = dh_subscriber_set_data_callback( + subscriber, + Some(on_data_received), + USER_DATA.as_ptr().cast_mut().cast(), + &mut error, + ); + if handle_client_error(error, "set data callback") { + let () = dh_subscriber_destroy(subscriber); + return None; + } + + let filter = dh_filter_create(); + if filter.is_null() { + error!("Failed to create filter"); + let () = dh_subscriber_destroy(subscriber); + return None; + } + + for topic in topics { + let mut error: *mut DHError = ptr::null_mut(); + let _ = dh_filter_add_topic_name(filter, topic.as_ptr(), &mut error); + if handle_client_error(error, "add topic name to filter") { + let () = dh_filter_destroy(filter); + let () = dh_subscriber_destroy(subscriber); + return None; + } + } + + let options = dh_subscribe_options_create(); + if options.is_null() { + error!("Failed to create subscription options"); + let () = dh_filter_destroy(filter); + let () = dh_subscriber_destroy(subscriber); + return None; + } + + let mut error: *mut DHError = ptr::null_mut(); + let _ = dh_subscribe_options_add_filter(options, filter, &mut error); + let () = dh_filter_destroy(filter); + if handle_client_error(error, "add filter to options") { + let () = dh_subscribe_options_destroy(options); + let () = dh_subscriber_destroy(subscriber); + return None; + } + + let () = dh_subscribe_options_set_enable_data_updates(options, true); + + let mut error: *mut DHError = ptr::null_mut(); + let _ = dh_subscriber_subscribe(subscriber, options, &mut error); + let () = dh_subscribe_options_destroy(options); + if handle_client_error(error, "subscribe to topic") { + let () = dh_subscriber_destroy(subscriber); + return None; + } + + Some(subscriber) +} + +/// Destroys `subscriber`, if any, then disconnects and destroys `client`. +unsafe fn cleanup_resources(client: *mut DHClient, subscriber: *mut DHSubscriber) { + debug_assert!(!client.is_null()); + if !subscriber.is_null() { + let () = dh_subscriber_destroy(subscriber); + } + + let mut error: *mut DHError = ptr::null_mut(); + let _ = dh_client_disconnect(client, &mut error); + let _ = handle_client_error(error, "client disconnect"); + let () = dh_client_destroy(client); +} + +extern "C" fn signal_handler(sig: c_int) { + if sig == SIGINT || sig == SIGTERM { + KEEP_RUNNING.store(false, Ordering::Relaxed); + } +} + +fn main() -> ExitCode { + acap_logging::init_logger(); + info!("Application started"); + + unsafe { + let _ = libc::signal(SIGINT, signal_handler as libc::sighandler_t); + let _ = libc::signal(SIGTERM, signal_handler as libc::sighandler_t); + } + + let topics = [TOPIC_NAME]; + + let Some(client) = (unsafe { initialize_client() }) else { + return ExitCode::FAILURE; + }; + let Some(subscriber) = (unsafe { setup_subscription(client, &topics) }) else { + let () = unsafe { cleanup_resources(client, ptr::null_mut()) }; + return ExitCode::FAILURE; + }; + + while KEEP_RUNNING.load(Ordering::Relaxed) { + let _ = unsafe { libc::pause() }; + } + + info!("Application terminated"); + let () = unsafe { cleanup_resources(client, subscriber) }; + ExitCode::SUCCESS +} From 4bd4d086da413ce1a0175a4c880ae17527b63193 Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Tue, 4 Aug 2026 07:25:42 +0200 Subject: [PATCH 4/7] f --- .devcontainer/Dockerfile | 3 ++- apps/object_consumer/manifest.json | 8 +++++++- apps/object_consumer/src/main.rs | 3 +++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 202c1783..82138dc4 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -2,7 +2,7 @@ ARG REPO=axisecp ARG SDK=acap-native-sdk # Keep in sync with `install-sdk.sh` and `on-host-workflow.yml`. ARG UBUNTU_VERSION=24.04 -# Keep in sync with `install-sdk.sh`. +# Keep in sync with `install-sdk.sh` and `AXIS_OS_VERSION` below. ARG VERSION=12.11.0 ARG BASE_IMAGE=debian:trixie-20260223 @@ -22,6 +22,7 @@ ENV \ SYSROOT_ARMV7HF=/opt/axis/acapsdk/sysroots/armv7hf # The above makes the below easier to read ENV \ + AXIS_OS_VERSION=12.11 \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER="aarch64-linux-gnu-gcc" \ CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUSTFLAGS="-C link-args=--sysroot=${SYSROOT_AARCH64}" \ CC_aarch64_unknown_linux_gnu="aarch64-linux-gnu-gcc" \ diff --git a/apps/object_consumer/manifest.json b/apps/object_consumer/manifest.json index 7c6569ca..830cbd94 100644 --- a/apps/object_consumer/manifest.json +++ b/apps/object_consumer/manifest.json @@ -4,8 +4,14 @@ "setup": { "appName": "object_consumer", "vendor": "Axis Communications", + "vendorId": "0123456789", "runMode": "never", - "version": "0.0.0" + "version": "0.0.0", + "compatibleOsVersions": [ + { + "max": "13" + } + ] } }, "resources": { diff --git a/apps/object_consumer/src/main.rs b/apps/object_consumer/src/main.rs index 616bc2c8..cbf4dba2 100644 --- a/apps/object_consumer/src/main.rs +++ b/apps/object_consumer/src/main.rs @@ -4,6 +4,9 @@ //! Unlike the C example, which relies on globals and `atexit`, resources are owned by `main` and //! released explicitly on every exit path. //! +//! Note that this example does not do anything on its own, and +//! its counterpart (`object_detector`) has yet to be ported. +//! //! [C example for consuming Device Data Hub data]: https://github.com/AxisCommunications/acap-native-sdk-examples/tree/main/device-data-hub/acap-communication/object-consumer use std::{ From 6c8dd667d1f1b9cae2dec2c8a4faa50d768f9c37 Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Tue, 4 Aug 2026 07:38:25 +0200 Subject: [PATCH 5/7] f --- Cargo.toml | 5 +- crates/datahub-sys/src/bindings.rs | 115 ----------------------------- 2 files changed, 2 insertions(+), 118 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 24200f3d..4378a2c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "apps/*", - "crates/*", + "apps/*", + "crates/*", ] resolver = "2" @@ -61,7 +61,6 @@ bbox-sys = { path = "crates/bbox-sys" } cargo-acap-build = { path = "crates/cargo-acap-build" } cli-version = { path = "crates/cli-version" } datahub-sys = { path = "crates/datahub-sys" } -device-manager = { path = "crates/device-manager" } larod-sys = { path = "crates/larod-sys" } licensekey = { path = "crates/licensekey" } licensekey-sys = { path = "crates/licensekey-sys" } diff --git a/crates/datahub-sys/src/bindings.rs b/crates/datahub-sys/src/bindings.rs index 10727bdd..dd9d63f7 100644 --- a/crates/datahub-sys/src/bindings.rs +++ b/crates/datahub-sys/src/bindings.rs @@ -1,32 +1,25 @@ /* automatically generated by rust-bindgen 0.69.5 */ -#[doc = " @brief API error codes enumeration\n\n Defines all possible error conditions that can occur when using the\n Device Data Hub C Client API."] pub type DHErrorCode = u32; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHError_t { _unused: [u8; 0], } -#[doc = " @brief Opaque error\n\n Represents an error condition with both an error code and descriptive message.\n This structure encapsulates error information with both an error code and message."] pub type DHError = DHError_t; extern "C" { - #[doc = " @brief Gets the error message from an error object\n\n Returns a human-readable description of the error condition.\n\n @param err The error object (must not be NULL)\n @return The error message string, or NULL if err is invalid"] pub fn dh_error_get_message(err: *const DHError) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets the error code from an error object\n\n Returns the specific error code that identifies the type of error.\n\n @param err The error object (must not be NULL)\n @return The error code, or DH_ERR_INVALID_PARAMS if err is invalid"] pub fn dh_error_get_code(err: *const DHError) -> DHErrorCode; } extern "C" { - #[doc = " @brief Converts an error code to its string representation\n\n Returns a human-readable string name for the given error code.\n For example, DH_ERR_INVALID_PARAMS returns \"DH_ERR_INVALID_PARAMS\".\n\n @param code The error code to convert\n @return The error code name as a string, or \"DH_ERR_UNKNOWN_ERROR\" if code is not recognized"] pub fn dh_error_code_to_string(code: DHErrorCode) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets a string representation of the complete error\n\n Returns a formatted string containing both the error code and message.\n The returned string is owned by the error object and should not be freed.\n\n @param err The error object (must not be NULL)\n @return Formatted error string, or NULL if err is invalid"] pub fn dh_error_to_string(err: *const DHError) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Destroys an error object\n\n Frees all resources associated with the error object.\n\n @param err The error object to destroy (can be NULL)"] pub fn dh_error_destroy(err: *mut DHError); } #[repr(C)] @@ -34,34 +27,26 @@ extern "C" { pub struct DHTimestamp_t { _unused: [u8; 0], } -#[doc = " @brief Opaque UTC timestamp\n\n Represents a point in time with nanosecond precision.\n Use dh_timestamp_get_as_sec() or dh_timestamp_get_as_ms() to retrieve the value."] pub type DHTimestamp = DHTimestamp_t; extern "C" { - #[doc = " @brief Creates a timestamp set to the current time\n\n @return New DHTimestamp set to the current UTC time, or NULL on memory allocation failure"] pub fn dh_timestamp_create() -> *mut DHTimestamp; } extern "C" { - #[doc = " @brief Sets the timestamp from a Unix epoch value in seconds\n\n @param timestamp The timestamp to update (must not be NULL)\n @param seconds Seconds since Unix epoch (1970-01-01 00:00:00 UTC)"] pub fn dh_timestamp_set_with_sec(timestamp: *mut DHTimestamp, seconds: i64); } extern "C" { - #[doc = " @brief Sets the timestamp from a Unix epoch value in milliseconds\n\n @param timestamp The timestamp to update (must not be NULL)\n @param milliseconds Milliseconds since Unix epoch (1970-01-01 00:00:00 UTC)"] pub fn dh_timestamp_set_with_ms(timestamp: *mut DHTimestamp, milliseconds: i64); } extern "C" { - #[doc = " @brief Updates the timestamp to the current time\n\n @param timestamp The timestamp to update (must not be NULL)"] pub fn dh_timestamp_set_current(timestamp: *mut DHTimestamp); } extern "C" { - #[doc = " @brief Gets the timestamp value as seconds since Unix epoch\n\n @param timestamp The timestamp (must not be NULL)\n @return Seconds since Unix epoch, or 0 if timestamp is NULL"] pub fn dh_timestamp_get_as_sec(timestamp: *const DHTimestamp) -> i64; } extern "C" { - #[doc = " @brief Gets the timestamp value as milliseconds since Unix epoch\n\n @param timestamp The timestamp (must not be NULL)\n @return Milliseconds since Unix epoch, or 0 if timestamp is NULL"] pub fn dh_timestamp_get_as_ms(timestamp: *const DHTimestamp) -> i64; } extern "C" { - #[doc = " @brief Destroys a timestamp\n\n Frees all resources associated with the DHTimestamp.\n\n @param timestamp The timestamp to destroy (can be NULL)"] pub fn dh_timestamp_destroy(timestamp: *mut DHTimestamp); } #[repr(C)] @@ -69,75 +54,62 @@ extern "C" { pub struct DHTopic_t { _unused: [u8; 0], } -#[doc = " @brief Opaque topic\n\n Represents a topic on the Device Data Hub. Topics are units of information used to\n exchange data between components. Each topic has a definition that describes\n its name, payload structure, QoS settings, etc."] pub type DHTopic = DHTopic_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHTopicData_t { _unused: [u8; 0], } -#[doc = " @brief Opaque topic data\n\n Represents the structured data content of a topic. The data is stored\n internally as JSON and can be manipulated using the topic_data_* functions."] pub type DHTopicData = DHTopicData_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHInstanceKeys_t { _unused: [u8; 0], } -#[doc = " @brief Opaque instance keys\n\n Represents a set of typed key-value pairs that uniquely identify a topic instance.\n Keys can hold either string or integer values"] pub type DHInstanceKeys = DHInstanceKeys_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHTopicInstance_t { _unused: [u8; 0], } -#[doc = " @brief Opaque topic instance\n\n Represents a specific instance of a topic. Instances are identified by\n a combination of key-value pairs and allow topics to contain multiple\n separate data streams (e.g., multiple detected objects, multiple I/O ports).\n TopicInstance objects represent specific instances of topics identified\n by their keys."] pub type DHTopicInstance = DHTopicInstance_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHTopicSample_t { _unused: [u8; 0], } -#[doc = " @brief Opaque topic sample\n\n Represents a single data sample within a topic or topic instance.\n Samples contain the actual data along with metadata like timestamps."] pub type DHTopicSample = DHTopicSample_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHTopicList_t { _unused: [u8; 0], } -#[doc = " @brief Opaque topic list\n\n Contains an array of topic names returned by topic listing operations.\n Must be freed using dh_topic_list_destroy()."] pub type DHTopicList = DHTopicList_t; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHTopicInstanceList_t { _unused: [u8; 0], } -#[doc = " @brief Opaque topic instance list\n\n Contains an array of topic instances returned by instance listing operations.\n Must be freed using dh_topic_instance_list_destroy()."] pub type DHTopicInstanceList = DHTopicInstanceList_t; extern "C" { - #[doc = " @brief Gets the name of a topic\n\n Returns the topic name as specified in the topic definition.\n\n @param topic The topic (must not be NULL)\n @return The topic name string, or NULL if invalid"] pub fn dh_topic_get_name(topic: *const DHTopic) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets the topic definition as a JSON string\n\n Returns a reference to the topic definition as a string in JSON format.\n The returned string is owned by the topic object and should not be freed.\n\n @param topic The topic (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return The topic definition JSON string, or NULL on error"] pub fn dh_topic_get_json_definition( topic: *const DHTopic, error: *mut *mut DHError, ) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Destroys a topic\n\n Frees resources associated with a topic. Does not delete the\n topic from the Device Data Hub, only releases local resources.\n\n @param topic The topic to destroy"] pub fn dh_topic_destroy(topic: *mut DHTopic); } extern "C" { - #[doc = " @brief Creates an empty topic data object\n\n Creates a new DHTopicData with an empty value.\n\n @return New DHTopicData, or NULL on memory allocation failure"] pub fn dh_topic_data_create() -> *mut DHTopicData; } extern "C" { - #[doc = " @brief Destroys a topic data object\n\n Frees all resources associated with the DHTopicData.\n\n @param topic_data The DHTopicData to destroy (can be NULL)"] pub fn dh_topic_data_destroy(topic_data: *mut DHTopicData); } extern "C" { - #[doc = " @brief Sets the value of topic data from JSON string\n\n Parses the JSON string and updates the topic data with the new value.\n\n @param topic_data The DHTopicData (must not be NULL)\n @param json_str JSON string containing the new value (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the input is not valid JSON\n\n **Possible error conditions:**\n - Invalid JSON string (`DH_ERR_INVALID_PARAMS`)"] pub fn dh_topic_data_set_json_data( topic_data: *mut DHTopicData, json_str: *const ::std::os::raw::c_char, @@ -145,43 +117,34 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Gets the topic data value as a JSON string\n\n Returns the current topic data value as a JSON-formatted string.\n The returned string is owned by the DHTopicData object and should not be freed.\n\n @param topic_data The DHTopicData (must not be NULL)\n @return JSON string representation, or NULL if invalid"] pub fn dh_topic_data_get_json_data( topic_data: *const DHTopicData, ) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets the topic name from a sample\n\n Returns the name of the topic this sample belongs to.\n The returned string is owned by the DHTopicSample and should not be freed.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The topic name string, or NULL if invalid"] pub fn dh_topic_sample_get_topic_name( topic_sample: *const DHTopicSample, ) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets the sample ID\n\n Returns the unique identifier for this sample within its topic.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The sample ID, or 0 if invalid"] pub fn dh_topic_sample_get_sample_id(topic_sample: *const DHTopicSample) -> u64; } extern "C" { - #[doc = " @brief Checks if the sample is historical data\n\n Returns whether this sample was received as part of cached history\n rather than as a live update.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return true if historical data, false otherwise or if invalid"] pub fn dh_topic_sample_is_historical(topic_sample: *const DHTopicSample) -> bool; } extern "C" { - #[doc = " @brief Gets the source timestamp\n\n Returns the timestamp provided by the producing application when\n the data was written.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The source timestamp, or NULL if invalid.\n The returned pointer is owned by the sample and must not be freed."] pub fn dh_topic_sample_get_timestamp(topic_sample: *const DHTopicSample) -> *const DHTimestamp; } extern "C" { - #[doc = " @brief Gets the topic data from a sample\n\n Returns the topic data contained in this sample.\n The returned pointer is owned by the TopicSample and should not be freed.\n\n @param topic_sample The TopicSample (must not be NULL)\n @return The topic data, or NULL if invalid"] pub fn dh_topic_sample_get_data(topic_sample: *const DHTopicSample) -> *const DHTopicData; } extern "C" { - #[doc = " @brief Creates an empty instance keys object\n\n @return New DHInstanceKeys with no keys set, or NULL on memory allocation failure"] pub fn dh_instance_keys_create() -> *mut DHInstanceKeys; } extern "C" { - #[doc = " @brief Destroys an instance keys object\n\n @param keys The DHInstanceKeys to destroy (can be NULL)"] pub fn dh_instance_keys_destroy(keys: *mut DHInstanceKeys); } extern "C" { - #[doc = " @brief Adds a string key-value pair\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param value The string value (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_instance_keys_add_string( keys: *mut DHInstanceKeys, name: *const ::std::os::raw::c_char, @@ -190,7 +153,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Adds an integer key-value pair\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param value The integer value\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_instance_keys_add_integer( keys: *mut DHInstanceKeys, name: *const ::std::os::raw::c_char, @@ -199,14 +161,12 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Checks whether a key exists\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name to look up (must not be NULL)\n @return true if the key exists, false otherwise"] pub fn dh_instance_keys_has_key( keys: *const DHInstanceKeys, name: *const ::std::os::raw::c_char, ) -> bool; } extern "C" { - #[doc = " @brief Gets the string value of a key\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param out_value Output pointer set to the string value on success (must not be NULL).\n The returned string is owned by the DHInstanceKeys and must not be freed.\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the key does not exist or is not a string"] pub fn dh_instance_keys_get_string( keys: *const DHInstanceKeys, name: *const ::std::os::raw::c_char, @@ -215,7 +175,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Gets the integer value of a key\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name (must not be NULL)\n @param out_value Output pointer set to the integer value on success (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the key does not exist or is not an integer"] pub fn dh_instance_keys_get_integer( keys: *const DHInstanceKeys, name: *const ::std::os::raw::c_char, @@ -224,7 +183,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Removes a key\n\n @param keys The DHInstanceKeys (must not be NULL)\n @param name The key name to remove (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false if the key does not exist"] pub fn dh_instance_keys_remove( keys: *mut DHInstanceKeys, name: *const ::std::os::raw::c_char, @@ -232,69 +190,55 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Gets the topic name of an instance\n\n Returns the name of the topic that this instance belongs to.\n\n @param topic_instance The TopicInstance (must not be NULL)\n @return Topic name string, or NULL if invalid"] pub fn dh_topic_instance_get_topic_name( topic_instance: *const DHTopicInstance, ) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets the instance keys\n\n Returns the key-value pairs that identify this specific instance.\n The returned DHInstanceKeys object is owned by the DHTopicInstance and should not be modified\n or freed.\n\n @param topic_instance The TopicInstance (must not be NULL)\n @return DHInstanceKeys object containing keys, or NULL if invalid"] pub fn dh_topic_instance_get_keys( topic_instance: *const DHTopicInstance, ) -> *const DHInstanceKeys; } extern "C" { - #[doc = " @brief Gets the instance information\n\n Returns additional information associated with this instance, if any.\n The returned string is owned by the DHTopicInstance and should not be modified or\n freed.\n\n @param topic_instance The DHTopicInstance (must not be NULL)\n @return The instance info string, or NULL if no info or invalid"] pub fn dh_topic_instance_get_info( topic_instance: *const DHTopicInstance, ) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Destroys a topic instance\n\n Frees all resources associated with the DHTopicInstance.\n\n @param topic_instance The DHTopicInstance to destroy (can be NULL)"] pub fn dh_topic_instance_destroy(topic_instance: *mut DHTopicInstance); } extern "C" { - #[doc = " @brief Gets the number of topics in the list\n\n @param list The DHTopicList (must not be NULL)\n @return The number of topics, or 0 if invalid"] pub fn dh_topic_list_get_count(list: *const DHTopicList) -> u32; } extern "C" { - #[doc = " @brief Gets a topic name by index\n\n Returns the topic name at the specified index.\n The returned string is owned by the DHTopicList and should not be freed.\n\n @param list The DHTopicList (must not be NULL)\n @param index Zero-based index into the list. Must be less than the value returned by\n dh_topic_list_get_count()\n @return The topic name string, or NULL if invalid or out of bounds"] pub fn dh_topic_list_get_name( list: *const DHTopicList, index: u32, ) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Frees a topic list\n\n Releases memory allocated for a topic list returned by dh_client_get_topic_list().\n\n @param topic_list The topic list to free (can be NULL)"] pub fn dh_topic_list_destroy(topic_list: *mut DHTopicList); } extern "C" { - #[doc = " @brief Gets the number of instances in the list\n\n @param list The DHTopicInstanceList (must not be NULL)\n @return The number of instances, or 0 if invalid"] pub fn dh_topic_instance_list_get_count(list: *const DHTopicInstanceList) -> u32; } extern "C" { - #[doc = " @brief Gets a topic instance by index\n\n Returns the topic instance at the specified index.\n The returned pointer is owned by the DHTopicInstanceList and should not be freed.\n\n @param list The DHTopicInstanceList (must not be NULL)\n @param index Zero-based index into the list. Must be less than the value returned by\n dh_topic_instance_list_get_count()\n @return The topic instance, or NULL if invalid or out of bounds"] pub fn dh_topic_instance_list_get( list: *const DHTopicInstanceList, index: u32, ) -> *const DHTopicInstance; } extern "C" { - #[doc = " @brief Frees a topic instance list\n\n Releases memory allocated for an instance list returned by\n dh_client_get_topic_instances().\n\n @param instance_list The instance list to free (can be NULL)"] pub fn dh_topic_instance_list_destroy(instance_list: *mut DHTopicInstanceList); } -#[doc = " @brief Consumer match status enumeration\n\n Indicates whether there are consumers interested in the data being produced.\n Used for consumer-producer matching to optimize resource usage."] pub type DHConsumerMatchStatus = u32; -#[doc = " @brief Production identifier type\n\n Unique identifier for a production registration. Used to track and manage\n producer-consumer matching registrations."] pub type DHProductionId = u64; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHWriter_t { _unused: [u8; 0], } -#[doc = " @brief Opaque writer handle\n\n Publishes data to a topic, handling both instanced and non-instanced topics\n with automatic instance management."] pub type DHWriter = DHWriter_t; -#[doc = " @brief Consumer match update callback function type for DHWriter\n\n Called when the consumer match status changes for a registered production.\n This allows applications to start/stop data production based on consumer interest.\n\n @param production_id Production ID that this update relates to\n @param status New consumer match status"] pub type DHOnConsumerMatchUpdateCallback = ::std::option::Option< unsafe extern "C" fn( production_id: DHProductionId, @@ -303,11 +247,9 @@ pub type DHOnConsumerMatchUpdateCallback = ::std::option::Option< ), >; extern "C" { - #[doc = " @brief Destroys a writer\n\n Automatically cleans up any registered productions and frees all resources\n associated with the writer. Active instances may be deleted based\n on their configuration.\n\n @param writer The writer to destroy (can be NULL)"] pub fn dh_writer_destroy(writer: *mut DHWriter); } extern "C" { - #[doc = " @brief Sets the consumer match update callback\n\n Registers a callback to be invoked when the consumer match status changes\n for any registered production. Pass NULL to remove the callback.\n\n @param writer The writer (must not be NULL)\n @param callback Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)"] pub fn dh_writer_set_consumer_match_update_callback( writer: *mut DHWriter, callback: DHOnConsumerMatchUpdateCallback, @@ -315,15 +257,12 @@ extern "C" { ); } extern "C" { - #[doc = " @brief Gets the name of a writer\n\n Returns the name that was specified when the writer was created.\n\n @param writer The writer (must not be NULL)\n @return The writer name, or NULL if invalid"] pub fn dh_writer_get_name(writer: *const DHWriter) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Gets the topic name this writer is initialized for\n\n Returns the name of the topic that was specified when the writer was\n created with dh_client_create_writer().\n The returned string is owned by the writer and must not be freed.\n\n @param writer The writer (must not be NULL)\n @return The topic name, or NULL if invalid"] pub fn dh_writer_get_topic_name(writer: *const DHWriter) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Writes data to the topic\n\n Writes the given data to the associated topic.\n\n If the topic is defined to have instances, the data will be written to\n the corresponding instance. If the instance doesn't exist it must be\n created first.\n\n If the topic doesn't support instances the data will be written to the\n default instance.\n\n If the sample number has reached the limit the oldest sample will be removed\n before adding the new sample.\n\n @param writer The writer (must not be NULL)\n @param instance_keys The instance keys identifying the target instance (can be NULL for topics without instances)\n @param topic_data The data to write (must not be NULL)\n @param timestamp Optional source timestamp (can be NULL for automatic timestamp)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_INSTANCE`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_INVALID_DATA`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_writer_write_data( writer: *mut DHWriter, instance_keys: *const DHInstanceKeys, @@ -333,7 +272,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Creates a topic instance explicitly\n\n Creates a new instance for the topic identified by the given key-value pairs.\n This is useful for pre-creating instances or when you need explicit control\n over instance lifecycle.\n\n @param writer The writer (must not be NULL)\n @param instance_keys Key-value pairs that uniquely identify the instance (must not be NULL)\n @param instance_info Optional string with additional instance information (can be NULL)\n @param delete_on_disconnect If true, the instance will be deleted when the client disconnects\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_KEYS`\n - `DH_ERR_INSTANCES_NOT_SUPPORTED`\n - `DH_ERR_INSTANCE_EXISTS`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_MAX_INSTANCES`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_writer_create_instance( writer: *mut DHWriter, instance_keys: *const DHInstanceKeys, @@ -343,7 +281,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Deletes a specific topic instance\n\n Removes the instance identified by the given key-value pairs and all its\n samples from the topic.\n\n @param writer The writer (must not be NULL)\n @param instance_keys Key-value pairs identifying the instance to delete (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_KEYS`\n - `DH_ERR_INSTANCES_NOT_SUPPORTED`\n - `DH_ERR_INVALID_INSTANCE`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_writer_delete_instance( writer: *mut DHWriter, instance_keys: *const DHInstanceKeys, @@ -351,11 +288,9 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Deletes all instances of the topic\n\n Removes all instances and their samples from the topic. Use with caution\n as this affects all data in the topic.\n\n @param writer The writer (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_KEYS`\n - `DH_ERR_INSTANCES_NOT_SUPPORTED`\n - `DH_ERR_INVALID_INSTANCE`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_writer_delete_all_instances(writer: *mut DHWriter, error: *mut *mut DHError) -> bool; } extern "C" { - #[doc = " @brief Registers production intent for consumer matching\n\n Registers the instance keys identifying the data this writer intends to produce.\n This enables consumer-producer matching, allowing the application to receive\n notifications when consumers are interested in this type of data. This is useful\n for optimizing resource usage by avoiding unnecessary data production.\n\n The application will be notified via the callback set with\n dh_writer_set_consumer_match_update_callback() when consumers show interest in\n or lose interest in the registered data.\n\n @param writer The writer (must not be NULL)\n @param instance_keys Key-value pairs identifying the instance to register production for\n (can be NULL). If NULL, all instances will be considered as matching.\n @param production_id Output parameter for the production ID (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_MAX_PRODUCTIONS`\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_writer_register_production( writer: *mut DHWriter, instance_keys: *const DHInstanceKeys, @@ -364,7 +299,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Unregisters a production registration\n\n Removes a previously registered production. No further consumer match\n notifications will be received for this production ID.\n\n @param writer The writer (must not be NULL)\n @param production_id The production ID to unregister\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_PRODUCTION`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_writer_unregister_production( writer: *mut DHWriter, production_id: DHProductionId, @@ -372,7 +306,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Gets the current consumer match status for a production\n\n Checks whether there are currently consumers interested in the data\n associated with the specified production registration.\n\n @param writer The writer (must not be NULL)\n @param production_id The production ID to check\n @param status Output parameter for the consumer match status (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_INVALID_PRODUCTION`"] pub fn dh_writer_get_consumer_match_status( writer: *mut DHWriter, production_id: DHProductionId, @@ -380,18 +313,14 @@ extern "C" { error: *mut *mut DHError, ) -> bool; } -#[doc = " @brief Topic update type enumeration\n\n Indicates whether a topic was created or deleted.\n Used in topic update callbacks."] pub type DHTopicUpdateType = u32; -#[doc = " @brief Topic instance update type enumeration\n\n Indicates whether a topic instance was created or deleted.\n Used in topic instance update callbacks."] pub type DHTopicInstanceUpdateType = u32; #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct DHSubscriber_t { _unused: [u8; 0], } -#[doc = " @brief Opaque subscriber handle\n\n Represents a subscriber for receiving data from one or more topics simultaneously."] pub type DHSubscriber = DHSubscriber_t; -#[doc = " @brief Topic update callback function type\n\n Called when a topic matching the subscription filters is created or deleted.\n\n @param topic_name Name of the topic that was updated (must not be NULL)\n @param update_type Whether the topic was created or deleted\n @param user_data User-provided context pointer"] pub type DHOnTopicUpdateCallback = ::std::option::Option< unsafe extern "C" fn( topic_name: *const ::std::os::raw::c_char, @@ -399,7 +328,6 @@ pub type DHOnTopicUpdateCallback = ::std::option::Option< user_data: *mut ::std::os::raw::c_void, ), >; -#[doc = " @brief Instance update callback function type\n\n Called when a topic instance matching the subscription filters is created or deleted.\n\n @param topic_instance The topic instance that was updated (must not be NULL)\n @param update_type Whether the instance was created or deleted\n @param user_data User-provided context pointer"] pub type DHOnInstanceUpdateCallback = ::std::option::Option< unsafe extern "C" fn( topic_instance: *const DHTopicInstance, @@ -407,7 +335,6 @@ pub type DHOnInstanceUpdateCallback = ::std::option::Option< user_data: *mut ::std::os::raw::c_void, ), >; -#[doc = " @brief Data update callback function type\n\n Called when new data matching the subscription filters is received.\n This is the primary callback for receiving topic data.\n\n @param topic_sample The received topic sample (must not be NULL)\n @param user_data User-provided context pointer"] pub type DHOnDataCallback = ::std::option::Option< unsafe extern "C" fn( topic_sample: *const DHTopicSample, @@ -419,18 +346,14 @@ pub type DHOnDataCallback = ::std::option::Option< pub struct DHFilter_t { _unused: [u8; 0], } -#[doc = " @brief Opaque subscription filter\n\n Represents a single filter used to match incoming samples. A filter carries\n three independent criteria — topic names, instance key sets, and data\n expressions — that are each logically OR-ed within the filter:\n a sample passes if its topic name matches **any** added topic name,\n its instance matches **any** added instance key set, or its data satisfies\n **any** added data expression.\n\n Create with dh_filter_create() and destroy with dh_filter_destroy()."] pub type DHFilter = DHFilter_t; extern "C" { - #[doc = " @brief Creates an empty filter\n\n @return New DHFilter with no criteria set, or NULL on memory allocation failure"] pub fn dh_filter_create() -> *mut DHFilter; } extern "C" { - #[doc = " @brief Destroys a filter\n\n Frees all resources associated with the filter.\n\n @param filter The filter to destroy (can be NULL)"] pub fn dh_filter_destroy(filter: *mut DHFilter); } extern "C" { - #[doc = " @brief Adds a topic name to the filter. A sample matches if its topic name matches any of the\n added topic names (logical OR).\n @param filter The filter to modify (must not be NULL)\n @param topic_name The topic name to add (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_filter_add_topic_name( filter: *mut DHFilter, topic_name: *const ::std::os::raw::c_char, @@ -438,7 +361,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Adds an instance key filter. A sample matches if it matches any of the added instance key\n filters (logical OR). Each instance key filter can contain multiple key-value pairs that must\n all match (logical AND).\n @param filter The filter to modify (must not be NULL)\n @param instance_keys The instance keys to add as a filter (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_filter_add_instance( filter: *mut DHFilter, instance_keys: *const DHInstanceKeys, @@ -446,7 +368,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Adds a data expression to the filter. A sample matches if it matches any of the data\n expressions. The data expression is an expression string applied to each incoming sample to\n filter based on sample data content. Multiple expressions are logically OR-ed: a sample passes\n if it satisfies **any** of the added expressions. The expression is a limited subset of\n operators. The following operators are supported: `()`, `==`, `!=`, `>`, `>=`, `<=`, `<`,\n `and`, `or`, `not`, `has()`. Data fields can be accessed using `.` notation,\n e.g. `.field.subfield`.\n @param filter The filter to modify (must not be NULL)\n @param data_expression The data expression (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_filter_add_data_expression( filter: *mut DHFilter, data_expression: *const ::std::os::raw::c_char, @@ -459,18 +380,14 @@ pub type DHStartFrom = u32; pub struct DHSubscribeOptions_t { _unused: [u8; 0], } -#[doc = " @brief Opaque subscription options\n\n Aggregates one or more DHFilter objects and update-enable flags into a\n single configuration passed to a subscribe call.\n Multiple filters are logically OR-ed: a sample matches if **any** filter\n matches.\n\n Create with dh_subscribe_options_create() and destroy with\n dh_subscribe_options_destroy()."] pub type DHSubscribeOptions = DHSubscribeOptions_t; extern "C" { - #[doc = " @brief Creates a subscription options object with default settings\n\n Default: no filters, all update types disabled, start from now.\n\n @return New DHSubscribeOptions, or NULL on memory allocation failure"] pub fn dh_subscribe_options_create() -> *mut DHSubscribeOptions; } extern "C" { - #[doc = " @brief Destroys a subscription options object\n\n @param options The options to destroy (can be NULL)"] pub fn dh_subscribe_options_destroy(options: *mut DHSubscribeOptions); } extern "C" { - #[doc = " @brief Adds a filter to the subscription options. Each filter is evaluated independently\n and matches if any filter matches (logical OR).\n @param options The subscription options (must not be NULL)\n @param filter The filter to add (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_subscribe_options_add_filter( options: *mut DHSubscribeOptions, filter: *const DHFilter, @@ -478,44 +395,37 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Enables or disables topic creation/deletion notifications\n\n @param options The options to modify (must not be NULL)\n @param enable true to enable, false to disable"] pub fn dh_subscribe_options_set_enable_topic_updates( options: *mut DHSubscribeOptions, enable: bool, ); } extern "C" { - #[doc = " @brief Enables or disables instance creation/deletion notifications\n\n @param options The options to modify (must not be NULL)\n @param enable true to enable, false to disable"] pub fn dh_subscribe_options_set_enable_instance_updates( options: *mut DHSubscribeOptions, enable: bool, ); } extern "C" { - #[doc = " @brief Enables or disables data update notifications\n\n @param options The options to modify (must not be NULL)\n @param enable true to enable, false to disable"] pub fn dh_subscribe_options_set_enable_data_updates( options: *mut DHSubscribeOptions, enable: bool, ); } extern "C" { - #[doc = " @brief Sets the starting point for data delivery\n\n @param options The options to modify (must not be NULL)\n @param start_from DH_START_FROM_NOW or DH_START_FROM_OLDEST"] pub fn dh_subscribe_options_set_start_from( options: *mut DHSubscribeOptions, start_from: DHStartFrom, ); } extern "C" { - #[doc = " @brief Destroys a subscriber\n\n Automatically unsubscribes if still subscribed and frees all resources\n associated with the subscriber.\n\n @param subscriber The subscriber to destroy (can be NULL)"] pub fn dh_subscriber_destroy(subscriber: *mut DHSubscriber); } extern "C" { - #[doc = " @brief Gets the name of a subscriber\n\n Returns the name that was specified when the subscriber was created.\n\n @param subscriber The subscriber (must not be NULL)\n @return The subscriber name, or NULL if invalid"] pub fn dh_subscriber_get_name(subscriber: *const DHSubscriber) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Sets the topic update callback\n\n Registers a callback to be invoked when a topic matching the subscription\n is created or deleted. Pass NULL to remove the callback.\n\n @param subscriber The subscriber (must not be NULL)\n @param on_topic_update Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_subscriber_set_topic_update_callback( subscriber: *mut DHSubscriber, on_topic_update: DHOnTopicUpdateCallback, @@ -524,7 +434,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Sets the instance update callback\n\n Registers a callback to be invoked when a topic instance matching the\n subscription is created or deleted. Pass NULL to remove the callback.\n\n @param subscriber The subscriber (must not be NULL)\n @param on_instance_update Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_subscriber_set_instance_update_callback( subscriber: *mut DHSubscriber, on_instance_update: DHOnInstanceUpdateCallback, @@ -533,7 +442,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Sets the data callback\n\n Registers a callback to be invoked when a data sample matching the\n subscription is received. Pass NULL to remove the callback.\n\n @param subscriber The subscriber (must not be NULL)\n @param on_data Callback function (can be NULL to remove)\n @param user_data Opaque pointer passed to the callback on each invocation (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_subscriber_set_data_callback( subscriber: *mut DHSubscriber, on_data: DHOnDataCallback, @@ -542,7 +450,6 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Subscribes to one or more topics with optional instance and data filtering\n\n Establishes a subscription to receive data from one or more topics,\n with optional filtering by instance keys and/or a data filter expression.\n\n @param subscriber The subscriber (must not be NULL)\n @param options Subscription options specifying filters and update types (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_DATA`\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_MAX_SUBSCRIPTIONS`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_subscriber_subscribe( subscriber: *mut DHSubscriber, options: *const DHSubscribeOptions, @@ -550,19 +457,14 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Unsubscribes from all topics\n\n Terminates all active subscriptions for this subscriber.\n No further callbacks will be received after this call completes successfully.\n\n @param subscriber The subscriber (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_REQUEST`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INVALID_SUBSCRIPTION`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_subscriber_unsubscribe( subscriber: *mut DHSubscriber, error: *mut *mut DHError, ) -> bool; } -#[doc = " @brief Enumeration of connection states for the Device Data Hub client.\n\n Represents the various states that the client's connection to the Device Data Hub\n can be in, such as disconnected, connected, or in the process of connecting."] pub type DHConnectionState = u32; -#[doc = " @brief Enumeration of available log levels for the Device Data Hub client.\n\n Defines the severity levels for logging messages, ordered from least verbose (OFF)\n to most verbose (DH_LOG_TRACE). Each level includes all messages from less verbose levels."] pub type DHLogLevel = u32; -#[doc = " @brief Enumeration of available log output targets.\n\n Specifies where log messages should be directed."] pub type DHLogTarget = u32; -#[doc = " @brief Connection state update callback function type\n\n Callback function called when the connection state changes.\n\n @param update The new connection state\n @param user_data User-provided data passed to dh_client_set_connection_update_callback()"] pub type DHOnConnectionUpdateCallback = ::std::option::Option< unsafe extern "C" fn(update: DHConnectionState, user_data: *mut ::std::os::raw::c_void), >; @@ -571,21 +473,17 @@ pub type DHOnConnectionUpdateCallback = ::std::option::Option< pub struct DHClient_t { _unused: [u8; 0], } -#[doc = " @brief Opaque client handle"] pub type DHClient = DHClient_t; extern "C" { - #[doc = " @brief Creates a new client instance\n\n Creates a new Device Data Hub client with the specified name.\n\n @param name The name of the client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the newly created client, or NULL on failure"] pub fn dh_client_create( name: *const ::std::os::raw::c_char, error: *mut *mut DHError, ) -> *mut DHClient; } extern "C" { - #[doc = " @brief Gets the name of the client\n\n Returns the name that was specified when the client was created.\n\n @param client The client (must not be NULL)\n @return The client name as a string, or NULL if client is invalid"] pub fn dh_client_get_name(client: *const DHClient) -> *const ::std::os::raw::c_char; } extern "C" { - #[doc = " @brief Sets the connection state update callback\n\n Registers a callback to receive connection state change notifications.\n\n @param client The client (must not be NULL)\n @param callback Callback function for connection state changes (can be NULL to remove)\n @param user_data User-provided data passed to the callback (can be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_client_set_connection_update_callback( client: *mut DHClient, callback: DHOnConnectionUpdateCallback, @@ -594,23 +492,18 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Connects the client synchronously to the Device Data Hub.\n\n This function attempts to establish a connection between the client and the\n Device Data Hub. The client must have the required access rights to connect.\n Once connected, the client can perform operations such as publishing data to\n and subscribing to topics on the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_ALREADY_CONNECTED`\n - `DH_ERR_CREDENTIAL_ERROR`\n - `DH_ERR_AUTHENTICATION_FAILED`\n - `DH_ERR_MAX_CLIENTS`\n - `DH_ERR_MAX_CONNECTIONS`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_connect(client: *mut DHClient, error: *mut *mut DHError) -> bool; } extern "C" { - #[doc = " @brief Disconnects the client from the Device Data Hub\n\n This method terminates the connection between the client and the Device Data Hub.\n All created writers/subscriptions will be invalidated and won't operate.\n\n @param client The client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_disconnect(client: *mut DHClient, error: *mut *mut DHError) -> bool; } extern "C" { - #[doc = " @brief Destroys a client instance\n\n Frees all resources associated with the client. The client will be\n automatically disconnected if still connected.\n This function will block until all ongoing callbacks have completed and no further callbacks will\n be invoked after it returns.\n\n @param client The client to destroy (can be NULL)"] pub fn dh_client_destroy(client: *mut DHClient); } extern "C" { - #[doc = " @brief Gets the current connection state\n\n Returns the detailed connection state of the client.\n\n @param client The client (must not be NULL)\n @return The current connection state"] pub fn dh_client_get_connection_state(client: *const DHClient) -> DHConnectionState; } extern "C" { - #[doc = " @brief Creates a new topic from the definition\n\n Creates a new topic on the Device Data Hub using a topic definition string.\n The format of the definition follows the JSON schema described in\n the main documentation.\n\n @param client The client (must not be NULL)\n @param file_path Path to a JSON file containing the topic definition (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created topic (caller must free with dh_topic_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_TOPIC_EXISTS`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_MAX_TOPIC`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_create_topic_from_file( client: *mut DHClient, file_path: *const ::std::os::raw::c_char, @@ -618,7 +511,6 @@ extern "C" { ) -> *mut DHTopic; } extern "C" { - #[doc = " @brief Creates a new topic from the definition\n\n Creates a new topic on the Device Data Hub using a topic definition string.\n The format of the definition follows the JSON schema described in\n the main documentation.\n\n @param client The client (must not be NULL)\n @param topic_def Topic definition in json string (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created topic (caller must free with dh_topic_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_TOPIC_EXISTS`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERR_MAX_TOPIC`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_create_topic( client: *mut DHClient, topic_def: *const ::std::os::raw::c_char, @@ -626,7 +518,6 @@ extern "C" { ) -> *mut DHTopic; } extern "C" { - #[doc = " @brief Deletes a topic from the Device Data Hub\n\n Permanently removes a topic and all its data from the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param topic_name The name of the topic to delete (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_AUTHORIZATION_FAILED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_delete_topic( client: *mut DHClient, topic_name: *const ::std::os::raw::c_char, @@ -634,14 +525,12 @@ extern "C" { ) -> bool; } extern "C" { - #[doc = " @brief Gets a list of available topics\n\n Retrieves a list of all topic names available on the Device Data Hub.\n The returned list must be freed using dh_topic_list_destroy().\n\n @param client The client (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the topic list (caller must free with dh_topic_list_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_get_topic_list( client: *mut DHClient, error: *mut *mut DHError, ) -> *mut DHTopicList; } extern "C" { - #[doc = " @brief Gets a topic by name\n\n Retrieves a topic for an existing topic on the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param topic_name The name of the topic to retrieve (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the topic (caller must free with dh_topic_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_get_topic( client: *mut DHClient, topic_name: *const ::std::os::raw::c_char, @@ -649,7 +538,6 @@ extern "C" { ) -> *mut DHTopic; } extern "C" { - #[doc = " @brief Gets topic instances for a topic\n\n Retrieves a list of all instances for the specified topic.\n The returned list must be freed using dh_topic_instance_list_destroy().\n\n @param client The client (must not be NULL)\n @param topic_name The name of the topic (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the instance list (caller must free with\n dh_topic_instance_list_destroy()), or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERROR_DATA_TOO_BIG`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_get_topic_instances( client: *mut DHClient, topic_name: *const ::std::os::raw::c_char, @@ -657,7 +545,6 @@ extern "C" { ) -> *mut DHTopicInstanceList; } extern "C" { - #[doc = " @brief Creates a writer for a specific topic\n\n Creates a new writer and initializes it for the specified topic.\n The topic must already exist on the Device Data Hub.\n\n @param client The client (must not be NULL)\n @param writer_name The name of the writer (must not be NULL)\n @param topic_name The name of the topic to write to (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created writer (caller must free with dh_writer_destroy()),\n or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INVALID_TOPIC`\n - `DH_ERR_NOT_CONNECTED`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_create_writer( client: *mut DHClient, writer_name: *const ::std::os::raw::c_char, @@ -666,7 +553,6 @@ extern "C" { ) -> *mut DHWriter; } extern "C" { - #[doc = " @brief Creates a topic data subscriber\n\n Creates a new data subscriber that can receive data from multiple topics.\n\n @param client The client (must not be NULL)\n @param subscriber_name The name of the topic subscriber (must not be NULL)\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return Pointer to the created topic subscriber (caller must free with\n dh_subscriber_destroy()), or NULL on failure\n\n **Possible error codes:**\n - `DH_ERR_INVALID_PARAMS`\n - `DH_ERR_INTERNAL_ERROR`"] pub fn dh_client_create_subscriber( client: *mut DHClient, subscriber_name: *const ::std::os::raw::c_char, @@ -674,7 +560,6 @@ extern "C" { ) -> *mut DHSubscriber; } extern "C" { - #[doc = " @brief Configures logging for the Device Data Hub client\n\n This method allows dynamic configuration of the logging settings\n for the Device Data Hub client at runtime.\n\n @param client The client (must not be NULL)\n @param level The log level to set\n @param target The log output target to set\n @param error Output parameter for error details on failure (can be NULL to ignore)\n @return true on success, false on failure"] pub fn dh_client_set_logging( client: *mut DHClient, level: DHLogLevel, From fe6f992c73a0b550b6785ebb473a17f3a0342830 Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Tue, 4 Aug 2026 07:54:25 +0200 Subject: [PATCH 6/7] checksums --- apps-aarch64.checksum | 1 + apps-aarch64.filesize | 1 + 2 files changed, 2 insertions(+) diff --git a/apps-aarch64.checksum b/apps-aarch64.checksum index 754f20f4..362efd33 100644 --- a/apps-aarch64.checksum +++ b/apps-aarch64.checksum @@ -9,6 +9,7 @@ eea87093d21a9c5975146e7e901b2af719751516 target-aarch64/acap/event_subscribe_1_ b094d400939f066dd4db602469c1f4fb242d4ca2 target-aarch64/acap/hello_world_0_0_0_aarch64.eap 0fec22df9046a67af4c0bb3f05e64a9e348d0cd6 target-aarch64/acap/inspect_env_0_0_0_aarch64.eap 44d11b7400ed107e3b091e3cd9b770336679c331 target-aarch64/acap/licensekey_handler_0_0_0_aarch64.eap +f6c8342784317c256fd0516efd9d52150d55c337 target-aarch64/acap/object_consumer_0_0_0_aarch64.eap 4fe894e74fb465817c3333dd4f3edfc7cca61766 target-aarch64/acap/object_detection_1_0_0_aarch64.eap 04dca71df69368834ce03d6c485597b115a00146 target-aarch64/acap/reverse_proxy_0_0_0_aarch64.eap 7e453ac8f014f7c54e7cae8d025b6d34509cad7a target-aarch64/acap/send_event_1_0_0_aarch64.eap diff --git a/apps-aarch64.filesize b/apps-aarch64.filesize index e25f9f6e..e5fb6c03 100644 --- a/apps-aarch64.filesize +++ b/apps-aarch64.filesize @@ -9,6 +9,7 @@ 1406 target-aarch64/acap/hello_world_0_0_0_aarch64.eap 1441 target-aarch64/acap/inspect_env_0_0_0_aarch64.eap 1430 target-aarch64/acap/licensekey_handler_0_0_0_aarch64.eap +1418 target-aarch64/acap/object_consumer_0_0_0_aarch64.eap 1408 target-aarch64/acap/object_detection_1_0_0_aarch64.eap 10315 target-aarch64/acap/reverse_proxy_0_0_0_aarch64.eap 3437 target-aarch64/acap/send_event_1_0_0_aarch64.eap From 50bb1799ca3c54974601b1028f4413c9943d938c Mon Sep 17 00:00:00 2001 From: AP Ljungquist Date: Tue, 4 Aug 2026 08:08:31 +0200 Subject: [PATCH 7/7] checksums --- apps-aarch64.checksum | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps-aarch64.checksum b/apps-aarch64.checksum index 362efd33..a587d398 100644 --- a/apps-aarch64.checksum +++ b/apps-aarch64.checksum @@ -9,7 +9,7 @@ eea87093d21a9c5975146e7e901b2af719751516 target-aarch64/acap/event_subscribe_1_ b094d400939f066dd4db602469c1f4fb242d4ca2 target-aarch64/acap/hello_world_0_0_0_aarch64.eap 0fec22df9046a67af4c0bb3f05e64a9e348d0cd6 target-aarch64/acap/inspect_env_0_0_0_aarch64.eap 44d11b7400ed107e3b091e3cd9b770336679c331 target-aarch64/acap/licensekey_handler_0_0_0_aarch64.eap -f6c8342784317c256fd0516efd9d52150d55c337 target-aarch64/acap/object_consumer_0_0_0_aarch64.eap +8982d13060a23b8e87fdbb803c5246d8afae0228 target-aarch64/acap/object_consumer_0_0_0_aarch64.eap 4fe894e74fb465817c3333dd4f3edfc7cca61766 target-aarch64/acap/object_detection_1_0_0_aarch64.eap 04dca71df69368834ce03d6c485597b115a00146 target-aarch64/acap/reverse_proxy_0_0_0_aarch64.eap 7e453ac8f014f7c54e7cae8d025b6d34509cad7a target-aarch64/acap/send_event_1_0_0_aarch64.eap