ensegre Posted May 18, 2016 Report Share Posted May 18, 2016 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 Quote Link to comment
ensegre Posted May 18, 2016 Author Report Share Posted May 18, 2016 Doh, by design: http://forums.ni.com/t5/LabVIEW/Possible-Bug-Ring-Constant-Typedef-not-updating/m-p/2400754 http://digital.ni.com/public.nsf/allkb/46CC27C828DB4205862570920062C125 However enums allow only sequential values... turns out that I'll have to revise what I was doing, which was happily using a lot of ring typedefs. Quote Link to comment
hooovahh Posted May 18, 2016 Report Share Posted May 18, 2016 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. Quote Link to comment
ensegre Posted May 18, 2016 Author Report Share Posted May 18, 2016 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... Quote Link to comment
ShaunR Posted May 18, 2016 Report Share Posted May 18, 2016 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. Quote Link to comment
hooovahh Posted May 18, 2016 Report Share Posted May 18, 2016 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. Quote Link to comment
ShaunR Posted May 18, 2016 Report Share Posted May 18, 2016 (edited) 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. Edited May 18, 2016 by ShaunR Quote Link to comment
ensegre Posted May 18, 2016 Author Report Share Posted May 18, 2016 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. Quote Link to comment
hooovahh Posted May 18, 2016 Report Share Posted May 18, 2016 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. Quote Link to comment
ensegre Posted May 18, 2016 Author Report Share Posted May 18, 2016 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: 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. Quote Link to comment
ShaunR Posted May 18, 2016 Report Share Posted May 18, 2016 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 Quote Link to comment
hooovahh Posted May 18, 2016 Report Share Posted May 18, 2016 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. Quote Link to comment
ShaunR Posted May 19, 2016 Report Share Posted May 19, 2016 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. Quote Link to comment
ensegre Posted May 19, 2016 Author Report Share Posted May 19, 2016 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. Quote Link to comment
Rolf Kalbermatter Posted May 22, 2016 Report Share Posted May 22, 2016 (edited) 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 May 22, 2016 by rolfk Quote Link to comment
ensegre Posted May 23, 2016 Author Report Share Posted May 23, 2016 (edited) 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 May 23, 2016 by ensegre Quote Link to comment
Rolf Kalbermatter Posted May 23, 2016 Report Share Posted May 23, 2016 (edited) 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! 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 May 23, 2016 by rolfk Quote Link to comment
ensegre Posted May 23, 2016 Author Report Share Posted May 23, 2016 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. Quote Link to comment
ShaunR Posted May 23, 2016 Report Share Posted May 23, 2016 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. Quote Link to comment
Yair Posted May 23, 2016 Report Share Posted May 23, 2016 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. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.