Jump to content

Text Ring typedef bug?


Recommended Posts

I think I've run into a nasty little bug, or perhaps I fail to grasp the higher reason for this. Seen on LV 2014 and 15 linux. Can someone confirm, so I escalate to NI support?

Let's say I have a Text Ring (or Menu Ring) typedef, and use it as a constant somewhere on a BD, like in the attached. At some point I modify the typedef in any way, like changing the text, editing the numeric values... and Apply Changes. The change is reflected in the control and in the indicator bound to that typedef, but not into the constant. Why? They are eventually, only if the constant is turned into a control and back.

ConstantControlIndicator.vi

TextRingTypedef.ctl

Link to comment

Yeah I don't like how the features of one I want in the other.  It some times means writing code that will go from a ring, to an enum.  Here is an idea exchange for making enums have non-sequential values.

http://forums.ni.com/t5/LabVIEW-Idea-Exchange/Add-sparse-enums-to-LabVIEW/idi-p/925224

Even so I would expect a strict-type def ring to update a constant, but I guess it doesn't.

Link to comment

Kudoed that idea, and the duplicate one mentioned in the discussion, for what helps.

So yes it turns that presenting the BD typedfd ring constant as typedef with a black ear is just a graphical mockery; on the BD, that object is treated as a non-typedefd, "Because type definitions identify only the data type". Only enums carry their legal range and labels as part of their data type.

My use case is to interface with a C library, whose (many and sparse in value) #defines may change across versions, and certainly do across bitnesses. I already had in place a dynamic way to create all the typedef.ctls I needed; only, I realized that all was fine when the typedefs were used for subvi controls and indicators, but not for BD constants, which were static. Now I'm scratching my head about whether I want to turn my generated typedefs into enums, then write a translation layer to obtain the nonsequential values, or what. Changing all my BD constants into dummy controls with defined default value doesn't look very elegant to me...

Link to comment
7 minutes ago, ensegre said:

Kudoed that idea, and the duplicate one mentioned in the discussion, for what helps.

So yes it turns that presenting the BD typedfd ring constant as typedef with a black ear is just a graphical mockery; on the BD, that object is treated as a non-typedefd, "Because type definitions identify only the data type". Only enums carry their legal range and labels as part of their data type.

My use case is to interface with a C library, whose (many and sparse in value) #defines may change across versions, and certainly do across bitnesses. I already had in place a dynamic way to create all the typedef.ctls I needed; only, I realized that all was fine when the typedefs were used for subvi controls and indicators, but not for BD constants, which were static. Now I'm scratching my head about whether I want to turn my generated typedefs into enums, then write a translation layer to obtain the nonsequential values, or what. Changing all my BD constants into dummy controls with defined default value doesn't look very elegant to me...

This also has other subtle implications such as you can change the ring strings at run-time whereas you cannot with enums. This means that if you want to translate a UI.......don't use Enums on the FP.

Link to comment

Yup, there are just some places where rings are so damned convenient.  I can have a list of common baud rates for hardware on the UI like 500K, 250K and it translates to a decimal value of 500,000, but then I can have an Other option where the user types in what they want and my code does its best to work with it.  Having to translate that back into enums, from enums back to rings, while supporting an "Other" mode, and saving and loading from disk can be a pain.  Come to think of it, this would probably be a good place for some OO and classes to handle all of this.  But still this is a bit of a band-aid when the IDE could support sparse enums.

Link to comment
1 hour ago, hooovahh said:

Yup, there are just some places where rings are so damned convenient.  I can have a list of common baud rates for hardware on the UI like 500K, 250K and it translates to a decimal value of 500,000, but then I can have an Other option where the user types in what they want and my code does its best to work with it.  Having to translate that back into enums, from enums back to rings, while supporting an "Other" mode, and saving and loading from disk can be a pain.  Come to think of it, this would probably be a good place for some OO and classes to handle all of this.  But still this is a bit of a band-aid when the IDE could support sparse enums.

 

One of the biggest (but not the only)  "pro" for enums used to be that case statements created readable case names when wired and for things like state-machines it was a  lot easier to see what was happening-readability. That really became a moot point when cases started to support strings. Enums are overrated and overused now IMO and pretty useless in flexible messaging architectures.

I was only recently turned on to the text combo box too which, when you consider string case structures, is an excellent enum replacement, I used it for the Encryption Compendium for LabVIEW since there is a predefined list of algorithms to choose from. Not only did it allow for using new algos if the user updates the binaries without having to wait for me to release a new version (they just type in the name) but it enabled paramterisation of the algorithms (like DH 1024 or DH 2048) for advanced uses. Catering for the different methods could have got real messy and much harder to use the standard set of algos without it.

Untitled1.png

 

Edited by ShaunR
Link to comment

hm, this is turning into a nice discussions about the relative merits and limitations of enums vs. rings. On which I agree all the way, but is not my original problem. That was, how to update "typedef" BD constants when their parent typedef is programmatically changed. IDE and prior to loading the involved VI set acceptable, at this point. Combo strings suffer of the same problem btw, as stressed by the KB linked above.

Now, unless there is some magical Xnode contraption, I think I would explore some VI scripting way - like scan every VI of the hierarchy for typedefd constants, unlink them and relink them from their parents, resave the VI. Looks like it will be much easier than a bloated translation layer, which implies extra code for every appearance of any constant.

 

Link to comment

In this case scripting is your friend.  You can have a tool that finds all instances of a type def, that is a constant, and then replace that constant with the updated one.  You might have a problem with typed controls that contain that type, that now need to be updated.

As for combo box, it isn't terrible, but again if I have a function that really only has three modes I want an enum and then I'll update it later if a 4th mode is added, and every place I have a case structure without that new case being handled, my VI will be broken (assuming no default case which you can do with an enum).  With a string you have to have a default case which handles all cases not handled.  Also there would be added code to handle if a case is called that doesn't exist, where I know that can't happen with an enum.  But again all of this could probably be wrapped in another abstraction layer and these issues could go away with more code.

Link to comment
2 hours ago, hooovahh said:

In this case scripting is your friend.  You can have a tool that finds all instances of a type def, that is a constant, and then replace that constant with the updated one.

Indeed, and this is what I'm tentatively coming up with:

RelinkAllRingTypedefConstants.png

My use case is that of passing to a certain CLN the value VIDIOC_S_FMT, which evaluates to 3234616837 with the 32bit library and to 3234878981 in the 64bit (at least in the 1.0.1-1 version of the library), as #defined in some obscure .h file, which I parse in order to generate the appropriate typedef. When I rebuild the typedef for the new platform, I need to care that the BD constant which represented my VIDIOC_S_FMT is updated to the correct item with the same label, in the new representation (as would happen if it was a changed enum). A different use case than the one you suggest above for combos.

You might have a problem with typed controls that contain that type, that now need to be updated.

I would say fortunately not, because they are controls. Differently from ring constants, controls are true typedefs. Ok, I could have not-typedefd BD cluster constants which contain this type, and I should traverse all clusters, and, and, but let's not exaggerate.

Link to comment
4 hours ago, ensegre said:

hm, this is turning into a nice discussions about the relative merits and limitations of enums vs. rings. On which I agree all the way, but is not my original problem. That was, how to update "typedef" BD constants when their parent typedef is programmatically changed. IDE and prior to loading the involved VI set acceptable, at this point. Combo strings suffer of the same problem btw, as stressed by the KB linked above.

Actually you already answered your own question  which was "No it isn't a bug" (the many surprises about typdefs?). Therefore you only have two options; put up with it or write a script.

I'm guessing most of us don't encounter it at all (like me, although I know it happens) or it's just a minor and rare annoyance not warranting a script. So you can't really blame us for wandering off and musing the merits of enums (which would solve your problem).

2 hours ago, hooovahh said:

In this case scripting is your friend.  You can have a tool that finds all instances of a type def, that is a constant, and then replace that constant with the updated one.  You might have a problem with typed controls that contain that type, that now need to be updated.

As for combo box, it isn't terrible, but again if I have a function that really only has three modes I want an enum and then I'll update it later if a 4th mode is added, and every place I have a case structure without that new case being handled, my VI will be broken (assuming no default case which you can do with an enum).  With a string you have to have a default case which handles all cases not handled.  Also there would be added code to handle if a case is called that doesn't exist, where I know that can't happen with an enum.  But again all of this could probably be wrapped in another abstraction layer and these issues could go away with more code.

Good point. Breaking a VI so you know where to modify is definitely an advantage of enums but are you still writing systems with lots of cases that need to be modified everywhere? I thought we had retired those organic architectures years ago

Link to comment
15 hours ago, ShaunR said:

Good point. Breaking a VI so you know where to modify is definitely an advantage of enums but are you still writing systems with lots of cases that need to be modified everywhere? I thought we had retired those organic architectures years ago

Certainly not lots of cases, but even if there are two it is some times easy to update one, and forget about the other.  Especially if some other developer is the one maintaining my code.

Link to comment
10 hours ago, ensegre said:

My use case is that of passing to a certain CLN the value VIDIOC_S_FMT, which evaluates to 3234616837 with the 32bit library and to 3234878981 in the 64bit (at least in the 1.0.1-1 version of the library), as #defined in some obscure .h file, which I parse in order to generate the appropriate typedef.

There is something wrong here. Constants don't change from 32 to 64 bit. Are you sure you are not looking at a pointer to a structure?

 

.....later, after some googling....

#define VIDIOC_S_FMT            _IOWR('V',  5, struct v4l2_format)

It's not a constant, it is a macro expansion to a function.You re inspecting a function pointer.

Link to comment
14 minutes ago, ShaunR said:

It's not a constant, it is a macro expansion to a function.You re inspecting a function pointer.

I'd say it's a constant, whose value is computed by the macro, defined in turn in another .h and telescopically. That results in different values, depending on bitness and architecture. But whatever, my point was for using the ring instead of an enum with such odd values.

Ah, not blaming anyone for wandering off... the discussion is instructive to me.

Link to comment
On 19-5-2016 at 9:25 AM, ShaunR said:

There is something wrong here. Constants don't change from 32 to 64 bit. Are you sure you are not looking at a pointer to a structure?

 

.....later, after some googling....


#define VIDIOC_S_FMT            _IOWR('V',  5, struct v4l2_format)

It's not a constant, it is a macro expansion to a function.You re inspecting a function pointer.

I would agree with ensegre. Macros with parameters may look like functions but they are not!. It's more evidenced by the uppercase name and the prepended underscore. It's sure not a guarantee, but it is common practice to name constants and constant macros with uppercase letters, and function names with all lowercase (or in Windows with the CamelCase names).

While it may seem a bad idea to make the constant different depending on the bitness this is probably made necessary by the fact that the structures can contain pointers which changes the size of the structure and the _IOWR() macro indicates actually a device driver ioctl() value and device drivers have always the bitness of the kernel even if the application which calls them may have a different bitness (and the driver is required to recognize that and translate any pointers accordingly to its 64 bit flat memory model.

Edited by rolfk
Link to comment

Thanks for reinforcing Rolf. In the specific case I know that is a constant because:

  • these numbers keep being the same on different platforms, on different instances of the application, in compiled C snippets as well as in LV CLN calls. No indication of pointers depending on relocation.
  • tracking the macro definition through the involved .h's , it boils down to a constant, much likely for the reason Rolf says. Pedantically: _IOWR() is defined in /usr/include/asm-generic/ioctl.h as
     #define _IOWR(type,nr,size)    _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size)))

    _IOC() is

    #define _IOC(dir,type,nr,size) \
    	(((dir)  << _IOC_DIRSHIFT) | \
    	 ((type) << _IOC_TYPESHIFT) | \
    	 ((nr)   << _IOC_NRSHIFT) | \
    	 ((size) << _IOC_SIZESHIFT))

    _IOC_TYPECHECK is

    #define _IOC_TYPECHECK(t) (sizeof(t))

    the various IOC_ constants

    #define _IOC_NRSHIFT	0
    #define _IOC_TYPESHIFT	(_IOC_NRSHIFT+_IOC_NRBITS)
    #define _IOC_SIZESHIFT	(_IOC_TYPESHIFT+_IOC_TYPEBITS)
    #define _IOC_DIRSHIFT	(_IOC_SIZESHIFT+_IOC_SIZEBITS)
    
    #define _IOC_NRBITS	8
    #define _IOC_TYPEBITS	8

    and so on. (wasn't there the story that someone writes a lot of C so that I don't have to?)

[show of hands, all this was for updating my https://lavag.org/files/file/232-lvvideo4linux/ which works, proof of the pudding. I resolved to tackle the typedef constants issue with a script in the lines of what I quoted above.]

Edited by ensegre
Link to comment
1 hour ago, ensegre said:

(wasn't there the story that someone writes a lot of C so that I don't have to?)

Well yes and he is still right! Nobody forced you to write a V4L interface library for LabVIEW! :D

And besides, think about how much C code you would have written if you had to write the UI part for all this too!

But in your tracing of the C macros I actually fail to see how the bitness would get into play.

Edited by rolfk
Link to comment
10 minutes ago, rolfk said:

But in your tracing of the C macros I actually fail to see how the bitness would get into play.

Uhm, maybe _IOC_TYPECHECK(v4l2_format) involves the length of some pointer buried within the v4l2_format structures, maybe it comes from elsewhere (/usr/include/asm-generic/ioctl.h #defines can be overridden). I meant, it's involved enough to see where it starts, for the rest I rely on the proficiency of v4l people.

Link to comment
1 hour ago, ensegre said:

Thanks for reinforcing Rolf. In the specific case I know that is a constant because:

  • these numbers keep being the same on different platforms, on different instances of the application, in compiled C snippets as well as in LV CLN calls. No indication of pointers depending on relocation.
  • tracking the macro definition through the involved .h's , it boils down to a constant, much likely for the reason Rolf says. Pedantically: _IOWR() is defined in /usr/include/asm-generic/ioctl.h as

    t someone writes a lot of C so that I don't have to?)

If you are sure, then  will bow to your better judgment and familiarity with the API. It's such an awful thing to do in modern APIs that I would have only expected that sort of thing in 1990s 32 bit code to thunk down to 16 bit :D.

It was (is) actually Aristos Queue's signature and it was C++ rather than C. Unless you are a masochist, you don't need write any C/C++ code in LabVIEW because ..... whats a pointer?

2 hours ago, ensegre said:

which works, proof of the pudding.

I'm sure Microsoft said exactly the same thing right before their first "Blue Screen of Death" report.

Link to comment
On 18.5.2016 at 7:29 PM, ensegre said:

Now, unless there is some magical Xnode contraption, I think I would explore some VI scripting way

You already wrote the scripting code, but one more option is to change the data type, which will also force an update. You should just make sure that the data type is large enough to keep the correct values (so U32->U64->Apply->U32->Apply). Also, I haven't checked, but I'm guessing this doesn't affect constants in VIs which aren't loaded when you make the change.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.