Mechanism and example for DDE direction up+

Hallo,

I am trying to understand the exact way the direction definition up+ works in the DDE.

Could you provide an description or example how and when I can use this??

Can I use it to generally reduce data size when transmitting histdata??

Thanks in advance

Cheers
Kaushik

The up+ just gives the device’s and backend’s storage managers some hint, that this container will most likely not occupy it’s full size declared in the DDE.

In this case, the systems behind try to gain some further data compaction for the cost of performance.

A typical use case for this are containers having a string field at their end which may heavily vary in length:

// DDE
#histdata6 myLog up+
    code u16
    message astr.200

The record’s .message field may have up to 200 characters, but this maximum extent won’t be often used. So it may make sense to invest a bit of CPU time to save storage memory.

IMPORTANT: up+ will have an effect only when the container ends with some string typed field (astr, ustr,…).

Thank you for your answer. Does this mean that I cannot use it for HistData containers with only float fields.

For example: I have a container:
#histadata0 mydata up+
data0 f32 default=NaN
data1 f32 default=NaN
data2 f32 default=NaN

If I record the container only with data0 and data1, will the system automatically add NaN to data2.

PS: I want to do this for 50 float values in one container and transmit only a subset. first 10 or 20 depending on user input.

Thanks and Cheers
Kaushik

ok, it is possible, but not in a trivial way :wink:

1. declare your container like that:

// DDE
#histdata5 my50floats up+
	fx[50]	f32.3 default=NAN     // float32 showing up /w 3 decimal digits

2. create your own write function

// DLO - replacement for DDE_my50floats_write() from dlo/~auto-dde.inc
stock DDE_my50floats_writeEx( const stamp=0, const o[DDE_my50floats], const numberOfFloatsToWrite) {
	dde_wbegin( DDE_my50floats_id);
	for( new i=0; i < numberOfFloatsToWrite; i++) dde_wf32( o.fx[i]);
	return dde_wend( stamp);
}

3. use your own write function DDE_my50floats_writeEx()
instead of the auto-generated one DDE_my50floats_write()

ps: note that it may be of advantage (computation performance, energy consumption) to use fixed-point numbers based on s32 instead of f32; in this case, the DLO writes s32 (for example values scaled by 1000). the backend portal and API offer automatic scaling when you state a field type of “s32.3”.

Hallo Andreas,

thank you for your reply.

eh, this may be problematic, since each channel has its own title and should be visible individually in the reports. The labels are stored in the configA-Block and is assigned then to each channel.

So basically the histdata-block looks like this:

#histdata5 mydata up+
       data0  u32 title=%configA%Title_1 default=NaN
       data1  u32 title=%configA%Title_2 default=NaN
       data2  u32 title=%configA%Title_3 default=NaN
       ...
       data50  u32 title=%configA%Title_50 default=NaN

Yes, I understand that I have to write my own write functions for this, and cannot use the generated DDE functions. But I have to do this anyway, since I have to decide how many values I have to write.

Can the Histdata container with up+ also contain data of different data types? I understand I have to provide default values for every channel.

Thanks in advance.

Cheers
Kaushik

some pro tip :wink: : you may use the nth-operator (analogous to the CSS nth() selector)

#histdata5 my50floats up+
	data[50]	f32.3 default=NAN title="%configA%Title_(n+1)"   // %Title_1, %Title_2,...

if you wish to organize your titles as an array, too (with 0-based offset):

#configA myTitles
	dummy	u8
	myTracks[50] {
		title astr.20
	}

#histdata5 my50floats up+
	data[50]	f32.3 default=NAN	title="%configA%myTracks[(n)].title"

Can the Histdata container with up+ also contain data of different data types?

yes, it can. But you need to keep the dynamic part (your array) at the end of the container. Pls be aware, that the static (none-dynamic) section can’t be extended in a later app version, since this would change the container’s binary footprint. to prevent from backward compatibility hell, you may eventually add some “reserved” bytes to your static section.

#histdata5 my50floats up+
	// static section
	staticA u8
	staticB astr.10

	reserved bin.10

	// dynamic section
	data[50]	f32.3 default=NAN	title="%configA%myTracks[(n)].title"

I understand I have to provide default values for every channel.

no, you do not need to. There is an implicit “all zero” default.

ps: sorry for my late reply, i was some days out for holiday

Hey Andreas,

This is a great tip!! I am definitely gonna use this!

I am gonna define a “NaN”-Default! So I may have to define default values for each channel anyway. :slight_smile:

No problem!! I am still experimenting a lot! So yours ideas are welcome anytime.

Cheers
Kaushik

Now here is another question for you:

Here the field myTracks is basically a “structure” inside the config block with string member “title”. Can I have multiple members inside? For example:

#configA myTitlesUnits
     TitleUnits[50] {
            title    astr.20
            unit    astr.8
     }

Is the “TitleUnits” considered as 1 field or 50 fields or 100 fields??

Can I use the same logic for histdata-Blocks?? For ex:

#histdata5 my50floats up+
	// static section
	staticA u8
	staticB astr.10

	reserved bin.10

	// dynamic section
	ModuleData[10]	{
          voltage f32.3 default=NAN	title="Module (n) Voltage"
          peakcurrent f32.2 default=NAN title="Module (n) Peak Current"
          power f32.2 default=NAN title="Module (n) Power"
    }

Looking forward to your answer! And Thank you!!

Cheers
Kaushik

Can I have multiple members inside?

yes - your example is just perfect.

note: due to restrictions of the DLO programming language:

  • DDE_xxx_read / DDE_xxx_write() may split your container into multiple parameters
  • structures always need to be an array (at least of dimension 1)

just try what you think may work. if there is something wrong, the DDE compiler will show up immediately with a warning or error message.

Is the “TitleUnits” considered as 1 field or 50 fields or 100 fields??
TitleUnits[50] {
title astr.20
unit astr.8
}

100 fields - the struct as well as the array are decomposed behind the scenes. you can see this, when accessing the raw backend API, where you get plain fieldnames like

"TitleUnits[0].title":...
"TitleUnits[0].unit":...
...
"TitleUnits[49].title":...
"TitleUnits[49].unit":...

and NOT an object like that:

{
    "TitleUnits": [
        { "title":..."unit":... },
        ...
        { "title":..."unit":... }
    ]
}

Can I use the same logic for histdata-Blocks??

yes

Thanks a lot Andreas!! I will let you know how my experiments work out!!

Cheers
Kaushik