I am attempting to write multiple nodes in a single request, however I have not found any documentation or examples on how to do that, every time I find anything regarding the issue, a single node is written. Based on my understanding of the open62541 library (which is not much), I've attempted to do this like so:
void Write_from_3_to_5_piece_queue() {
char NodeID[128];
char NodeID_backup[128];
char aux[3];
bool bool_to_write = false;
strcpy(NodeID_backup, _BaseNodeID);
strcat(NodeID_backup, "POU.AT2.piece_queue["); // this is where I want to write, I need only to append the array index in which to write
UA_WriteRequest wReq;
UA_WriteValue my_nodes[3]; // this is where I start to make things up, I'm not sure this is the correct way to do it
my_nodes[0] = *UA_WriteValue_new();
my_nodes[1] = *UA_WriteValue_new();
my_nodes[2] = *UA_WriteValue_new();
strcpy(NodeID, NodeID_backup);
strcat(NodeID, "3]"); //append third index of array (will write to piece_queue[3])
my_nodes[0].nodeId = UA_NODEID_STRING_ALLOC(_nodeIndex, NodeID);
my_nodes[0].attributeId = UA_ATTRIBUTEID_VALUE;
my_nodes[0].value.hasValue = true;
my_nodes[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
my_nodes[0].value.value.storageType = UA_VARIANT_DATA_NODELETE;
my_nodes[0].value.value.data = &bool_to_write;
strcpy(NodeID, NodeID_backup);
strcat(NodeID, "4]");
my_nodes[1].nodeId = UA_NODEID_STRING_ALLOC(_nodeIndex, NodeID);
my_nodes[1].attributeId = UA_ATTRIBUTEID_VALUE;
my_nodes[1].value.hasValue = true;
my_nodes[1].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
my_nodes[1].value.value.storageType = UA_VARIANT_DATA_NODELETE;
my_nodes[1].value.value.data = &bool_to_write;
strcpy(NodeID, NodeID_backup);
strcat(NodeID, "5]");
my_nodes[2].nodeId = UA_NODEID_STRING_ALLOC(_nodeIndex, NodeID);
my_nodes[2].attributeId = UA_ATTRIBUTEID_VALUE;
my_nodes[2].value.hasValue = true;
my_nodes[2].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
my_nodes[2].value.value.storageType = UA_VARIANT_DATA_NODELETE;
my_nodes[2].value.value.data = &bool_to_write;
UA_WriteRequest_init(&wReq);
wReq.nodesToWrite = my_nodes;
wReq.nodesToWriteSize = 3;
UA_WriteResponse wResp = UA_Client_Service_write(_client, wReq);
UA_WriteResponse_clear(&wResp);
UA_WriteRequest_clear(&wReq);
return;
}
At first I didn't have much hope that this would work, but it turns out this actually writes the values that I wish. The problem is that on UA_WriteRequest_clear(&wReq); I trigger an exception in the open62541 library:
Also, I know I can write multiple values to arrays specifically, even though in this particular example that would fix my issue, that's not what I mean to do, this example is just to simplify my problem. Just suppose I have a multi-type structure and I want to write to it, all in a single request. I appreciate any help!
First of all, this is bad:
UA_WriteValue my_nodes[3];
my_nodes[0] = *UA_WriteValue_new();
my_nodes[1] = *UA_WriteValue_new();
my_nodes[2] = *UA_WriteValue_new();
my_nodes is already created on the stack, and then you are copying the content of a new object into it by dereferencing. This definitely leads to memory leaks. You probably want to use UA_WriteValue_init() instead.
Never ever dereference the return value of a new() function.
Let's go bottom up:
UA_WriteRequest_clear(&wReq) is recursively freeing all content of the wReq steucture.
This means that it will also call:
UA_Array_delete(wReq.nodesToWrite, wReq.nodesToWriteSize, ...)
which in turn calls UA_free(wReq.nodesToWrite)
And you have:
wReq.nodesToWrite = my_nodes;
with
UA_WriteValue my_nodes[3];
This means that you are assigning a variable, which lives on the stack to a pointer, and later this pointer is freed. free can only delete stuff which is on the heap and not stack, and therefore it fails.
You have two options now:
If you still want to use the stack trick the UA_clear in thinking that the variable is empty:
wReq.nodesToWrite = NULL;
wReq.nodesToWriteSize = 0;
UA_clear(&wReq);
Put the nodes on the heap:
Instead of
UA_WriteValue my_nodes[3]; use Something like UA_WriteValue *my_nodes = (UA_WriteValue*)UA_malloc(sizeof(UA_WriteValue)*3);
Also I strongly recommend that you either use valgrind or clang memory sanitizer to avoid all these memory issues.
I have a problem in flutter I want to do a search bar and I have a response to an api and I want to show data from server that contains a text from search bar my problem is where method doesn't work with List any ideas ?
Looking at your comment, there is no where method on String types. Instead of the for loop, you want something along these lines:
// Remove the for loop
// for(var i = 0; i <map.length; i++) { _results = jsonDecode(map[i]['address']).where((p)=>p.startsWith(query)).toList(); }
// Do this instead
_results = map.where((item) => item['address'].startsWith(query)).toList();
You should now be able to ditch the for loop.
I am using postman to get response header value like below:
var data = postman.getResponseHeader("Location") . //value is "http://aaa/bbb" for example
I can print the value via console.log(data) easily.
However, what I really want is "bbb". So I need some substring() type of function. And apparently 'data' is not a javascript string type, because data.substring(10) for example always return null.
Does anyone what i need to do in this case?
If any postman API doc existing that explains this?
You can set an environment variable in postman. try something like
var data = JSON.parse(postman.getResponseHeader("Location"));
postman.setEnvironmentVariable("dataObj", data.href.substring(10));
You have the full flexibility of JavaScript at your fingertips here, so just split the String and use the part after the last /:
var data = pm.response.headers.get("Location").split("/").pop());
See W3 school's documentation of split and pop if you need more in depth examples of JavaScript internals.
Some initial thought - I needed a specific part of the "Location" header like the OP, but I had to also get a specific value from that specific part.
My header would look something like this
https://example.com?code_challenge_method=S256&redirect_uri=https://localhost:8080&response_type=code&state=vi8qPxcvv7I&nonce=uq95j99qBCGgJvrHjGoFtJiBoo
And I need the "state" value to pass on to the next request as a variable
var location_header = pm.response.headers.get("Location");
var attributes = location_header.split('&');
console.log(attributes);
var len = attributes.length;
var state_attribute_value = ""
var j = 0;
for (var i = 0; i < len; i++) {
attribute_key = attributes[i].split('=')[0];
if (attribute_key == "state") {
state_attribute_value = attributes[i].split('=')[1];
}
j = j + 1;
}
console.log(state_attribute_value);
pm.environment.set("state", state_attribute_value);
Might you get the point here, "split" is the choice to give you some array of values.
If the text you are splitting is always giving the same array length it should be easy to catch the correct number
I everybody,
I'm trying to parse a text file into matlab: it consists of several blocks (START_BLOCK/END_BLOCK) where are allocated strings (variable) and values (associated to the previous variables).
An example is this:
START_BLOCK_EXTREMEWIND
velocity_v1 29.7
velocity_v50 44.8
velocity_vred1 32.67
velocity_vred50 49.28
velocity_ve1 37.9
velocity_ve50 57
velocity_vref 50
END_BLOCK_EXTREMEWIND
Currently, my code is:
fid = fopen('test_struct.txt','rt');
C = textscan(fid,'%s %f32 %*[^\n]','CollectOutput',true);
C{1} = reshape(C{1},1,numel(C{1}));
C{2} = reshape(C{2},1,numel(C{2}));
startIdx = find(~cellfun(#isempty, regexp(C{1}, 'START_BLOCK_', 'match')));
endIdx = find(~cellfun(#isempty, regexp(C{1}, 'END_BLOCK_', 'match')));
assert(all(size(startIdx) == size(endIdx)))
extract_parameters = #(n)({C{1}{startIdx(n)+1:endIdx(n) - 1}});
parameters = arrayfun(extract_parameters, 1:numel(startIdx), 'UniformOutput', false);
s = cell2struct(cell(size(parameters{1})),parameters{1}(1:numel(parameters{1})),2);
s.velocity_v1 = C{2}(2);
s.velocity_v50 = C{2}(3);
s.velocity_vred1 = C{2}(4);
s.velocity_vred50 = C{2}(5);
s.velocity_ve1 = C{2}(6);
s.velocity_ve50 = C{2}(7);
s.velocity_vref = C{2}(8);
It works, but it's absolutely static. I would rather have a code able to:
1. check the existence of blocks --> as already implemented;
2. the strings are to be taken as fields of the structure;
3. the numbers are meant to be the attributes of each field.
Finally, if there is more than one block, there should be and iteration about those blocks to get the whole structure.
It's the first time I approach structure coding at all, so please be patient.
I thank you all in advance.
Kindest regards.
It sounds like you will want to make use of dynamic field names. If you have a struct s, a string fieldName that stores the name of a field, and fieldVal which holds the value that you'd like to set for this field, then you can use the following syntax to perform the assignment:
s.(fieldName) = fieldVal;
This MATLAB doc provides further info.
With this in mind, I took a slightly different approach to parse the text. I iterated through the text with a for loop. Although for loops are sometimes frowned upon in MATLAB (since MATLAB is optimized for vectorized operations), I think in this case it helps to make the code cleaner. Furthermore, my understanding is that if you are having to make use of arrayfun, then replacing this with a for loop probably won't really cause much of a performance hit, anyway.
The following code will convert each block in the text to a struct with the specified fields and values. These resulting "block" structs are then added to a higher-level "result" struct.
fid = fopen('test_struct.txt','rt');
C = textscan(fid,'%s %f32 %*[^\n]','CollectOutput',true);
fclose(fid);
paramNames = C{1};
paramVals = C{2};
curBlockName = [];
inBlock = 0;
blockCount = 0;
%// Iterate through all of the entries in "paramNames". Each block will be a
%// new struct that is then added to a high-level "result" struct.
for i=1:length(paramNames)
curParamName = paramNames{i};
isStart = ~isempty(regexp(curParamName, 'START_BLOCK_', 'match'));
isEnd = ~isempty(regexp(curParamName, 'END_BLOCK_', 'match'));
%// If at the start of a new block, create a new struct with a single
%// field - the BlockName (as specified by the text after "START_BLOCK_"
if(isStart)
assert(inBlock == 0);
curBlockName = curParamName(length('START_BLOCK_') + 1:end);
inBlock = 1;
blockCount = blockCount + 1;
s = struct('BlockName', curBlockName);
%// If at the end of a block, add the struct that we've just populated to
%// our high-level "result" struct.
elseif(isEnd)
assert(inBlock == 1);
inBlock = 0;
%// EDIT - storing result in "structure of structures"
%// rather than array of structs
%// s_array(blockCount) = s;
result.(curBlockName) = s;
%// Otherwise, assume that we are inside of a block, so add the current
%// parameter to the struct.
else
assert(inBlock == 1);
s.(curParamName) = paramVals(i);
end
end
%// Results stored in "result" structure
Hopefully this answers your question... or at least provides some helpful hints.
I edited my code today and now it almost works as meant to be:
clc, clear all, close all
%Find all row headers
fid = fopen('test_struct.txt','r');
row_headers = textscan(fid,'%s %*[^\n]','CommentStyle','%','CollectOutput',1);
row_headers = row_headers{1};
fclose(fid);
%Find all attributes
fid1 = fopen('test_struct.txt','r');
attributes = textscan(fid1,'%*s %s','CommentStyle','%','CollectOutput',1);
attributes = attributes{1};
fclose(fid1);
%Collect row headers and attributes in a single cell
parameters = [row_headers,attributes];
%Find all the blocks
startIdx = find(~cellfun(#isempty, regexp(parameters, 'BLOCK_START_', 'match')));
endIdx = find(~cellfun(#isempty, regexp(parameters, 'BLOCK_END_', 'match')));
assert(all(size(startIdx) == size(endIdx)))
%Extract fields between BLOCK_START_ and BLOCK_END_
extract_fields = #(n)(parameters(startIdx(n)+1:endIdx(n)-1,1));
struct_fields = arrayfun(extract_fields, 1:numel(startIdx), 'UniformOutput', false);
%Extract attributes between BLOCK_START_ and BLOCK_END_
extract_attributes = #(n)(parameters(startIdx(n)+1:endIdx(n)-1,2));
struct_attributes = arrayfun(extract_attributes, 1:numel(startIdx), 'UniformOutput', false);
for i = 1:numel(struct_attributes)
s{i} = cell2struct(struct_attributes{i},struct_fields{i},1);
end
Now, in the end, I get a cell of stuctures that could, let's say, fulfill my requirements. The only point that I would like to improve is:
- Give each structure the name of the respective block.
Does anybody have valuable hints?
Thank you all for supporting me.
Regards,
Francesco
I am trying to loop over an array called meta.
I am having issues with checking if an element exists. In this array sometimes the length is present and sometimes it is not. I am trying to get something like this to work:
for (i=1;i LTE ArrayLen(meta);i=i+1) {
if (meta[i].length==undefined) {
maxLen = '1';
}
else
{
maxLen = meta[i].length;
}
}
I cannot seem to get the syntax right.
I think you want a structkeyexists.
if (structkeyexists(meta[i],"length") ....