-
Notifications
You must be signed in to change notification settings - Fork 0
datapaths
To provide an alternative way to order the forwards (and generics) in a way that corresponds more with how the data passes through them.
- Structure the various forwards according to how the data goes through them instead of the type of forward
- Make the definition of the forwards shorter by omitting id and src
- At runtime reload with retention of targets
pf:reload,id
Both pf and paths are valid:
-
pf:addblank,id,src,format
Adds a blank id with the given src to settings.xml- Options:
- F/M/E -> Filter,Math or Editor node without subnodes
- f/m/e -> Filter,Math or Editor with a subnode for each letter (so ff = two subnodes)
- i/r/t -> Add a generic with the given subnodes (integer,real,text) and id same as path
- Examples:
- FmmE -> Adds a filter node, then a math node with two subnodes followed by an Editor node
- Fiirr -> Adds a filter node, then a generic with two integer subnodes and two real subnodes
- Options:
-
pf:addgen,pathid<:genid>,format,delimiter
Add a generic with either the given id or path id as id, and format likegens:addblank
- Format: Letter of subnode(i,r,t), index of value in array and name. All concatenated, multiple delimited with ,
- Example: i1temp,r3offset = integer at index 1 with name temp, real at index 3 with name offset
- Format: Letter of subnode(i,r,t), index of value in array and name. All concatenated, multiple delimited with ,
-
pf:reload,id
Reload the path with the given id -
pf:list
Get a list of all currently existing paths -
pf:debug,stepnr
Request the output data of the given step in the path (first one is 0)
Suggest you get the data from a stream with id 'random': This is test 5 Hello World?
For the example we'll:
- alter that 5 to 6
- replace 'This' with 'That'
Before datapaths the xml would look like this.
<dcafs>
<filters>
<filter id="getthis" src="raw:random" type="start">This</filter>
</filters>
<editors>
<editor id="this_to_that" src="filter:getthis" type="replace" find="This">That</editor>
</editors>
<maths>
<math id="incr" src="edit:thisthat" delimiter=" ">i3=i3+1</math>
</maths>
</dcafs>
To see the result we use math:incr
.
To achieve the same result with paths:
<!-- Src of a forward is the output of the previous one or the path src if it's the first one.
Filters are a special case, but this will be shown later -->
<dcafs>
<paths>
<path id="alter" src="raw:random" > <!-- The src is what the first node gets -->
<filter type="start">This</filter> <!-- src used is raw:random-->
<edit type="replace" find="this">That</edit> <!-- src is data from previous step-->
<math delimiter=" ">i3=i3+1</math><!-- src is data from previous step -->
</path>
</paths>
</dcafs>
To see the result we use path:alter
because this cmd will give the target to the last step.
So this way, you can omit code that dcafs can safely assume.
What is also possible is to keep the path in a separate file.
<!-- in the main settings.xml -->
<dcafs>
<paths>
<path id="alter" src="raw:random" import="paths/alter.xml"/>
</paths>
</dcafs>
Then a separate file alter.xml with the structure.
<dcafs>
<path id="alter"> <!-- if there's only one path, then the id can be omitted -->
<!-- same content -->
</path>
</dcafs>
The above was meant as a drop in replacement for a collection of math,filter,editors that start with data from a src.
But it's also possible that the path generates the src instead of receiving it. This can be used for debugging a path
(use raw data) or building a custom datastream for a connected device.
For example:
<path id="custom">
<customsrc interval="1s">Hello World!</customsrc>
<!-- More than one is possible -->
<customsrc interval="5s">Hello World?</customsrc>
</path>
That would give the next step (or whatever requests path:custom) 'Hello World!' every second and 'Hello World?' every 5s.
If the interval is 1s, this doesn't need to be specified.
What's also possible:
<path id="custom">
<customsrc interval="1s">Hello World {double:datapoint}</customsrc>
</path>
Difference being that the path will look for a doubleval with the id datapoint and insert this.
Or a cmd:
<path id="cmdrepeating">
<customsrc type="cmd" interval="1s">st</customsrc>
</path>
This will assume the value (in this case 'st') is a command and will output the result from it. With this example it would be possible to see status result in the telnet window updated every second.
And finally, reading from a file.
<path id="readfile">
<!-- file:3 means that the source is a file and every read is of three lines -->
<customsrc type="file:3" interval="1s">/raw/olddata.txt</customsrc>
</path>
Let's assume you have multiple temperature sensors and want to see an overview of these
<path id="custom">
<customsrc type="cmd" interval="1s">{utc} T1:{double:temp1}°C T2:{double:temp2}°C T3:{double:temp3}°C</customsrc>
</path>
Or a tad more complicated, for this we'll use an optional feature and that's defining the delimiter as an attribute in the path making it the default delimiter for all the steps (default because you can still override it).
<path id="custom" delimiter=",">
<customsrc type="cmd" interval="1s">{utc},{double:temp1},{double:temp2},{double:temp3},1</customsrc>
<math>i4=(i1+i2+i3)/3</math> <!-- Calculate the average, and put it where the 1 was -->
<editor type="resplit">i0 T1:i1°C T2:i2°C T3:i2°C Avg:i3°C</editor>
</path>
It's allowed to add relevant generics inside the path node, but these need to have a proper id.
The generic lookup code will also check the imported files for generics.
Easiest way to add these is with pf:addgen,pathid<:genid>,format,delimiter
(check cmd list in the beginning).
To add the generic below, the command would be pf:addgen,alter:randomstore,r3value,
<dcafs>
<paths>
<path id="alter" src="raw:random"> <!-- The src is what the first node gets -->
<filter type="start">This</filter> <!-- dcafs doesn't find an id so will assume alter_f1 nor a src so use the raw:random-->
<editor type="replace" find="this">That</editor> <!-- again assume id alter_e1 but this time use filter:alter_f1 as src-->
<math delimiter=" ">i3=i3+1</math><!-- id will be math:alter_m1 and src edit:alter_e1 -->
<generic id="randomstore" delimiter=" ">
<real index="3">value</real>
</generic>
</path>
</paths>
</dcafs>
Because both id and src aren't overwritten if they are already present, if we wanted to do something with the other
sentence (Hello World), this can be done in the same path.
Let's replace world with Europe.
<dcafs>
<paths>
<path id="alter" src="raw:random"> <!-- The src is what the first node gets -->
<filter id="filt" type="start">This</filter>
<editor type="replace" find="this">That</editor>
<math delimiter=" ">i3=i3+1</math>
<editor src="!filt" type="replace" find="world">Europe</editor>
<!-- It's also possible to not give an id and refer to the generated one (pathid_nodeindex)-->
<filter type="start">This</filter>
<editor type="replace" find="this">That</editor>
<math delimiter=" ">i3=i3+1</math>
<!-- Reverse of the first node so !alter_0 -->
<editor src="!alter_0" type="replace" find="world">Europe</editor>
</path>
</paths>
</dcafs>
This also changes the data given from path:alter
because this always returns the result of the last node (if any)!
It's possible to set a default delimiter for all steps in the path.
<dcafs>
<paths>
<!-- This earlier example that uses a space a delimiter in two steps -->
<path id="alter" src="raw:random">
<filter type="start">This</filter>
<editor type="replace" find="this">That</editor>
<math delimiter=" ">i3=i3+1</math>
<generic id="randomstore" delimiter=" ">
<real index="3">value</real>
</generic>
</path>
<!-- Could also be done like this -->
<path id="alter" src="raw:random" delimiter=" ">
<filter type="start">This</filter>
<editor type="replace" find="this">That</editor>
<math>i3=i3+1</math>
<generic id="randomstore">
<real index="3">value</real>
</generic>
</path>
</paths>
</dcafs>
Given that filters have the option to forward the discarded data instead of the allowed data (filter:!id), it's possible to omit id and src from any filter element that should use the reverse of the previous one.
<dcafs>
<paths>
<!-- This earlier example that uses a space a delimiter in two steps -->
<path id="alter" src="raw:random">
<filter id="thisf" type="start">This</filter>
<editor>alter someting</editor>
<math>calc something</math>
<filter src="filter:!thisf" type="start">That</filter>
</path>
<!-- Could also be done like this -->
<path id="alter" src="raw:random" delimiter=" ">
<filter type="start">This</filter>
<editor>alter someting</editor>
<math>calc something</math>
<filter type="start">That</filter> <!-- Will get the data discarded by the previous filter instead of the math result -->
</path>
<!-- But if two filters are consecutive, they follow the standard rule -->
<path id="alter" src="raw:random" delimiter=" ">
<filter type="start">This</filter>
<filter type="end">.</filter> <!-- Will get the data that starts with This and check if it ends with a dot -->
</path>
</paths>
</dcafs>
- Getting to know dcafs
- Filterforward
- MathForward
- EditForward (todo)
- Combining
- TaskManager
- LabelWorker
- CommandPool
- DebugWorker
- Realtimevalues
- IssuePool