From 3bca23a59cd5bbacbaefe9dd459998f7f2e278bd Mon Sep 17 00:00:00 2001 From: Nicolas Menard Date: Tue, 13 Aug 2024 10:17:07 -0400 Subject: [PATCH] add support for passing raw attributes to readings (#291) --- micro-rdk-ffi/include/micrordk.h | 18 +++++++++++ micro-rdk-ffi/src/ffi/config.rs | 52 ++++++++++++++++++++++++++++++-- micro-rdk-ffi/src/ffi/sensor.rs | 46 ++++++++++++++++++++++++++-- micro-rdk/src/common/config.rs | 2 +- 4 files changed, 113 insertions(+), 5 deletions(-) diff --git a/micro-rdk-ffi/include/micrordk.h b/micro-rdk-ffi/include/micrordk.h index bb4129ada..8054bdefa 100644 --- a/micro-rdk-ffi/include/micrordk.h +++ b/micro-rdk-ffi/include/micrordk.h @@ -30,6 +30,8 @@ typedef struct get_readings_context get_readings_context; */ typedef struct hashmap_cstring_ptr hashmap_cstring_ptr; +typedef struct raw_attributes raw_attributes; + typedef struct viam_server_context viam_server_context; /* @@ -60,6 +62,16 @@ extern "C" { */ enum viam_code config_get_string(struct config_context *ctx, const char *key, char **out); +/* + Returns a pointer to the raw attribute structure of a component config + */ +struct raw_attributes *config_get_raw_attributes(struct config_context *ctx); + +/* + Free a raw_attributes structure previously obtained with `config_get_raw_attributes` + */ +enum viam_code config_raw_attributes_free(struct raw_attributes *attrs); + /* Free a string allocated by a successful call to `config_get_string` */ @@ -186,6 +198,12 @@ enum viam_code get_readings_add_string(struct get_readings_context *ctx, const char *key, const char *value); +/* + This function adds raw attributes to a sensor reading request + */ +enum viam_code get_readings_add_raw_attributes(struct get_readings_context *ctx, + const struct raw_attributes *raw_attrs); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/micro-rdk-ffi/src/ffi/config.rs b/micro-rdk-ffi/src/ffi/config.rs index 53b3167be..26fd887ba 100644 --- a/micro-rdk-ffi/src/ffi/config.rs +++ b/micro-rdk-ffi/src/ffi/config.rs @@ -1,6 +1,9 @@ -use std::ffi::{c_char, c_int, CStr, CString}; +use std::{ + collections::HashMap, + ffi::{c_char, c_int, CStr, CString}, +}; -use micro_rdk::common::config::{AttributeError, ConfigType}; +use micro_rdk::common::config::{AttributeError, ConfigType, Kind}; use super::errors; @@ -9,6 +12,9 @@ pub struct config_context<'a> { pub(crate) cfg: ConfigType<'a>, } +#[allow(non_camel_case_types)] +pub struct raw_attributes(pub(crate) HashMap); + /// Get a string from the attribute section of a sensor configuration /// if found the content of the string will be written to `out` /// @@ -40,6 +46,48 @@ pub unsafe extern "C" fn config_get_string( unsafe { *out = c_str }; errors::viam_code::VIAM_OK } + +/// Returns a pointer to the raw attribute structure of a component config +/// pointers remains valid until `config_raw_attributes_free` is called. +/// Free the structure with `config_raw_attributes_free` when done using it. +/// +/// # Safety +/// `ctx` must be a valid pointer +#[no_mangle] +pub unsafe extern "C" fn config_get_raw_attributes( + ctx: *mut config_context, +) -> *mut raw_attributes { + if ctx.is_null() { + return std::ptr::null_mut(); + } + + let ctx = unsafe { &mut *ctx }; + + let ConfigType::Dynamic(cfg) = ctx.cfg; + if let Some(attrs) = &cfg.attributes { + return Box::into_raw(Box::new(raw_attributes(attrs.clone()))); + } + + std::ptr::null_mut() +} + +/// Free a raw_attributes structure previously obtained with `config_get_raw_attributes` +/// +/// # Safety +/// `attrs` must be a valid pointer +#[no_mangle] +pub unsafe extern "C" fn config_raw_attributes_free( + attrs: *mut raw_attributes, +) -> errors::viam_code { + if attrs.is_null() { + return errors::viam_code::VIAM_INVALID_ARG; + } + + drop(Box::from_raw(attrs)); + + errors::viam_code::VIAM_OK +} + /// Free a string allocated by a successful call to `config_get_string` /// /// # Safety diff --git a/micro-rdk-ffi/src/ffi/sensor.rs b/micro-rdk-ffi/src/ffi/sensor.rs index cd0b3b5d7..f1327c64f 100644 --- a/micro-rdk-ffi/src/ffi/sensor.rs +++ b/micro-rdk-ffi/src/ffi/sensor.rs @@ -1,9 +1,10 @@ use micro_rdk::{ common::{ + config::Kind, sensor::{GenericReadingsResult, Readings, Sensor, SensorError}, status::Status, }, - google::protobuf::Value, + google::protobuf::{value, Value}, DoCommand, }; use std::{ @@ -11,7 +12,10 @@ use std::{ ffi::{c_char, c_int, c_uchar, c_uint, c_void, CStr}, }; -use super::{config::config_context, errors::viam_code}; +use super::{ + config::{config_context, raw_attributes}, + errors::viam_code, +}; #[allow(non_camel_case_types)] type config_callback = extern "C" fn(*mut config_context, *mut c_void, *mut *mut c_void) -> c_int; @@ -223,3 +227,41 @@ pub unsafe extern "C" fn get_readings_add_string( viam_code::VIAM_OK } + +// converts a config::Kind to value::Kind purposefully skipping "nested" Kinds +fn into_value(kind: Kind) -> value::Kind { + match kind { + Kind::BoolValue(b) => value::Kind::BoolValue(b), + Kind::NullValue(n) => value::Kind::NullValue(n), + Kind::NumberValue(f) => value::Kind::NumberValue(f), + Kind::StringValue(s) => value::Kind::StringValue(s), + _ => value::Kind::NullValue(0), + } +} + +/// This function can be use by a sensor during the call to `get_readings_callback` to add a `raw_attributes` struct +/// to get_readings +/// +/// # Safety +/// `ctx`, and `raw_attrs` and `value` must be valid pointers for the duration of the call +#[no_mangle] +pub unsafe extern "C" fn get_readings_add_raw_attributes( + ctx: *mut get_readings_context, + raw_attrs: *const raw_attributes, +) -> viam_code { + if ctx.is_null() || raw_attrs.is_null() { + return viam_code::VIAM_INVALID_ARG; + } + let ctx = unsafe { &mut *ctx }; + let attrs = unsafe { &*raw_attrs }; + for attr in &attrs.0 { + let _ = ctx.readings.insert( + attr.0.clone(), + Value { + kind: Some(into_value(attr.1.clone())), + }, + ); + } + + viam_code::VIAM_OK +} diff --git a/micro-rdk/src/common/config.rs b/micro-rdk/src/common/config.rs index 4d78c0326..05f23242a 100755 --- a/micro-rdk/src/common/config.rs +++ b/micro-rdk/src/common/config.rs @@ -155,7 +155,7 @@ impl TryFrom<&Kind> for Kind { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum Kind { NullValue(i32), NumberValue(f64),