03-21-2025 07:32 AM - edited 03-21-2025 07:49 AM
@Asasafuchi wrote:
How does this code work with certification? Do I need to modify the rust scripts so that I can add certification file paths, security policies etc?
Well, there are two possibilities. One is to add appropriate attributes to the ClientBuilder and pass as parameters to VI (like NI OPC UA does). Another way - to load everything from config file (like I did with Server), then configure security in config file (advantage - you don't need to change LabVIEW code in this case). Anyway I added load Client from config:
but didn't check this with real certificates, may be at weekend.
Regard your previous question about Browser - you can handle OnChange Event, then you will get Tag, and frm this Tag you can get detailed NodeInfo with all attributes.
LabVIEW code looks like this:
Rust code behind:
#[unsafe(no_mangle)]
pub extern "C" fn lv_get_node_info(
rt_ptr: *mut Runtime,
session_in: *mut Arc<Session>,
id_u32: u32,
id_str: *const i8,
ns: u16,
id_type: u32,
mut lv_str: LStrHandle,
) -> i32 {
check_runtime!(rt_ptr);
unsafe {
let rt = &mut *rt_ptr;
if !session_in.is_null() {
let session = &mut *session_in;
let id: NodeId;
match id_type {
1 => id = NodeId::new(0, id_u32).into(), //so works so far
2 => id = NodeId::new(ns, cstr_to_string!(id_str)).into(),
_ => return ERR_INVALID_TYPE,
}
let r = rt.block_on(async {
session
.read(
&read_value_ids(
&[
AttributeId::Value,
AttributeId::DisplayName,
AttributeId::BrowseName,
//AttributeId::NodeClass, //lot of Attributes available
//AttributeId::NodeId,
//AttributeId::Historizing,
//AttributeId::ArrayDimensions,
//AttributeId::Description,
//AttributeId::ValueRank,
//AttributeId::DataType,
//AttributeId::AccessLevel,
//AttributeId::UserAccessLevel, //and so on...
],
&id,
),
TimestampsToReturn::Both,
0.0,
)
.await
.unwrap()
});
let mut i = 0;
let mut output = String::new();
while i < r.len() {
write!(&mut output, "Attribute {}: {:?}\n", i, r[i])
.expect("Failed to get attribute");
i = i + 1;
}
let len = output.len();
string_resize(1, 1, &mut lv_str as *mut LStrHandle, len);
let c_headers = match CString::new(output) {
Ok(cs) => cs,
Err(_) => return -1, // failed to convert to C string
};
MoveBlockChar(c_headers.as_ptr(), (**lv_str).str.as_mut_ptr(), len);
(**lv_str).cnt = len as i32;
}
}
return 0;
}
And this is how it works (for this demo I added second variable "MySine" as Double):
Then this output can be parsed and nicely formatted in LabVIEW "like UA Expert".
And yes, namespace 2 is set to default on most terminals.
Unfortunately can't spend much time on it, because busy with other heavy weight projects.
Seems to be Virus Scanner in trouble, I added password opcua2025 to the archive, let see