Structure in a Structure
TUTech
Posts: 70
Still working on P2 Practical. I was told in another post that it's ok to ask for help.
This will compile, but I get an error C10571 Converting type [string] to [CHAR]. I don't see where I'm converting.
DEFINE_TYPE
STRUCTURE sLightInfo
{
INTEGER nIntensity
INTEGER nFadeTime
}
STRUCTURE sScene
{
char cSName
sLightInfo Lt_Zone1
sLightInfo Lt_Zone2
sLightInfo Lt_Zone3
sLightInfo Lt_Zone4
}
DEFINE_VARIABLE
sScene Preset[3]
Define_Start
Preset[1].cSName = 'Scene1';
Preset[1].Lt_Zone1.nIntensity = 50;
Preset[1].Lt_Zone1.nFadeTime = 3;
Preset[1].Lt_Zone2.nIntensity = 50;
Preset[1].Lt_Zone2.nFadeTime = 3;
Preset[1].Lt_Zone3.nIntensity = 50;
Preset[1].Lt_Zone3.nFadeTime = 3;
Preset[1].Lt_Zone4.nIntensity = 50;
Preset[1].Lt_Zone4.nFadeTime = 3;
Preset[2].cSName = 'Scene2';
Preset[2].Lt_Zone1.nIntensity = 50;
Preset[2].Lt_Zone1.nFadeTime = 3;
Preset[2].Lt_Zone2.nIntensity = 50;
Preset[2].Lt_Zone2.nFadeTime = 3;
Preset[2].Lt_Zone3.nIntensity = 30;
Preset[2].Lt_Zone3.nFadeTime = 3;
Preset[2].Lt_Zone4.nIntensity = 30;
Preset[2].Lt_Zone4.nFadeTime = 3;
Preset[3].cSName = 'Scene3';
Preset[3].Lt_Zone1.nIntensity = 100;
Preset[3].Lt_Zone1.nFadeTime = 3;
Preset[3].Lt_Zone2.nIntensity = 100;
Preset[3].Lt_Zone2.nFadeTime = 3;
Preset[3].Lt_Zone3.nIntensity = 100;
Preset[3].Lt_Zone3.nFadeTime = 3;
Preset[3].Lt_Zone4.nIntensity = 100;
Preset[3].Lt_Zone4.nFadeTime = 3;
The initialization should go in the ONLINE statement but I put it in Start to make sure it will compile first.
This will compile, but I get an error C10571 Converting type [string] to [CHAR]. I don't see where I'm converting.
DEFINE_TYPE
STRUCTURE sLightInfo
{
INTEGER nIntensity
INTEGER nFadeTime
}
STRUCTURE sScene
{
char cSName
sLightInfo Lt_Zone1
sLightInfo Lt_Zone2
sLightInfo Lt_Zone3
sLightInfo Lt_Zone4
}
DEFINE_VARIABLE
sScene Preset[3]
Define_Start
Preset[1].cSName = 'Scene1';
Preset[1].Lt_Zone1.nIntensity = 50;
Preset[1].Lt_Zone1.nFadeTime = 3;
Preset[1].Lt_Zone2.nIntensity = 50;
Preset[1].Lt_Zone2.nFadeTime = 3;
Preset[1].Lt_Zone3.nIntensity = 50;
Preset[1].Lt_Zone3.nFadeTime = 3;
Preset[1].Lt_Zone4.nIntensity = 50;
Preset[1].Lt_Zone4.nFadeTime = 3;
Preset[2].cSName = 'Scene2';
Preset[2].Lt_Zone1.nIntensity = 50;
Preset[2].Lt_Zone1.nFadeTime = 3;
Preset[2].Lt_Zone2.nIntensity = 50;
Preset[2].Lt_Zone2.nFadeTime = 3;
Preset[2].Lt_Zone3.nIntensity = 30;
Preset[2].Lt_Zone3.nFadeTime = 3;
Preset[2].Lt_Zone4.nIntensity = 30;
Preset[2].Lt_Zone4.nFadeTime = 3;
Preset[3].cSName = 'Scene3';
Preset[3].Lt_Zone1.nIntensity = 100;
Preset[3].Lt_Zone1.nFadeTime = 3;
Preset[3].Lt_Zone2.nIntensity = 100;
Preset[3].Lt_Zone2.nFadeTime = 3;
Preset[3].Lt_Zone3.nIntensity = 100;
Preset[3].Lt_Zone3.nFadeTime = 3;
Preset[3].Lt_Zone4.nIntensity = 100;
Preset[3].Lt_Zone4.nFadeTime = 3;
The initialization should go in the ONLINE statement but I put it in Start to make sure it will compile first.
0
Comments
DEFINE_TYPE
STRUCTURE sLightInfo
{
INTEGER nIntensity
INTEGER nFadeTime
}
STRUCTURE sScene
{
char cSName
sLightInfo Lt_Zone
}
DEFINE_VARIABLE
sScene Preset[3]
Define_Start
Preset[1].cSName = 'Scene1';
Preset[1].Lt_Zone[1].nIntensity = 50;
Preset[1].Lt_Zone[1].nFadeTime = 3;
Preset[1].Lt_Zone[2].nIntensity = 50;
Preset[1].Lt_Zone[2].nFadeTime = 3;
Preset[1].Lt_Zone[3].nIntensity = 50;
Preset[1].Lt_Zone[3].nFadeTime = 3;
Preset[1].Lt_Zone[4].nIntensity = 50;
Preset[1].Lt_Zone[4].nFadeTime = 3;
Preset[2].cSName = 'Scene2';
Preset[2].Lt_Zone[1].nIntensity = 50;
Preset[2].Lt_Zone[1].nFadeTime = 3;
Preset[2].Lt_Zone[2].nIntensity = 50;
Preset[2].Lt_Zone[2].nFadeTime = 3;
Preset[2].Lt_Zone[3].nIntensity = 30;
Preset[2].Lt_Zone[3].nFadeTime = 3;
Preset[2].Lt_Zone[4].nIntensity = 30;
Preset[2].Lt_Zone[4].nFadeTime = 3;
Preset[3].cSName = 'Scene3';
Preset[3].Lt_Zone[1].nIntensity = 100;
Preset[3].Lt_Zone[1].nFadeTime = 3;
Preset[3].Lt_Zone[2].nIntensity = 100;
Preset[3].Lt_Zone[2].nFadeTime = 3;
Preset[3].Lt_Zone[3].nIntensity = 100;
Preset[3].Lt_Zone[3].nFadeTime = 3;
Preset[3].Lt_Zone[4].nIntensity = 100;
Preset[3].Lt_Zone[4].nFadeTime = 3;
so, using your variable/structure format:
EDITED TO ADD: I just copy/pasted this into NS and it does indeed compile.
Paul
I tend to use structures if the data I'm referring to is stored in some kind of XML-ish way. For example: if I happen to be writing everything to/from the Netlinx "Disk" or if I'm pushing/pulling from an SQL database or something. To my eye, structures kind of have that same feel and writing code to move the data to/from the structure and the database is easy to read and write code.
I don't think I've every nested a structure for any other reason.
Also, it may well be that the OP's example is just that: an example for the sake of the discussion. Who knows. But, I too wouldn't do it this way either.
For that use it makes sense.
One of the really handy things you can do with a structure is pass an element of it as a parameter to a function.
Another great thing you can do is Variable_to_string on a structure to write it to disk and string_to_variable to read it from disk into a variable in a couple lines of code. The thing that you have to remember here is that NetLinx does not automatically set array lengths on any arrays other than strings (and only when you set the whole string). So you need to manually set array lengths before calling variable_to_string. I tried variable_to_xml in the past but it was unable to encode nested structures. I have even used variable_to_string to send structures into modules using SEND_COMMAND and/or SEND_STRING. I tried it as an experiment and was pleasantly surprised by how quick and reliable it was. I have production code that uses this methodology.
This might be a good topic to bring up with the folks at AMX in NX Firmware. The whole notion of data structs comes from our friends out there in Object-oriented land. In that realm, the advantage of structures is that they can be 'ragged' where a simple multi-dimensional array cannot. Plus, they just look and feel like Object-oriented stuff. with a struct the inner parts are referred to by human-readable names. In a mult-dimensional array you kind of have to remember what the column s and rows represent and its entirely possible to get the wrong.
I don't know for a fact but I think Netlinx cannot be ragged. A sturct of X dimensions and Y cells takes up the same mem space as an equal array. Also, I've never really seen any noticeable degradation of speed using either method. I typically try to write code not necessarily for it's logical ellegance but more towards efficiency of processor time. But, I will say I choose between MD Arrays vs. Stucts simply for the looks.
Just because in a struct you can mix and match different data type you want, using MD arrays youll need to make per data type. Is that still a trade off that you accept?
It depends on the compiler and the memory management. Some systems pad memory when using structs so that the struct takes up a defined space, others store it as is so it takes longer to read. But a large struct with large char arrays inside another struct, will slow things down when compared to nonencapsulated structs doing the same thing. I was parsing HTTP packets, writing to structs within a struct with the appropriate data, and then reading the data to populate buttons on touch panels. It was too slow to be usable. Since I had written so much code already, I figured I'd give it one last shot and remove the struct within a struct method and break them out into nonencapsulated structs and see if it made any difference. It took it from unusable to usable. Here is one struct I used. I had some of these fields in other structs and put them inside this one, but then broke it out so no struct within a struct was needed:
Paul
Project[Houses[Rooms[TVs[TV[input].iCurrentInput]]]] = cnHDMI
All that pointer following comes at a cost.
Here is what GNU says about the GCC compiler: [h=4]2.4.5 Size of Structures[/h] The size of a structure type is equal to the sum of the size of all of its members, possibly including padding to cause the structure type to align to a particular byte boundary. The details vary depending on your computer platform, but it would not be atypical to see structures padded to align on four- or eight-byte boundaries. This is done in order to speed up memory accesses of instances of the structure type.
As a GNU extension, GCC allows structures with no members. Such structures have zero size.
If you wish to explicitly omit padding from your structure types (which may, in turn, decrease the speed of structure memory accesses), then GCC provides multiple methods of turning packing off. The quick and easy method is to use the -fpack-struct compiler option. For more details on omitting packing, please see the GCC manual which corresponds to your version of the compiler.
I don't know if the AMX compiler pads structs or not. Nested structs and recursion are two things I stay away from when writing Netkinx code.
Paul
Send_String dvLights,"'FADEDIM,'itoa(Preset[1].Lt_Zone1.nIntensity),','itoa(Preset[1].Lt_Zone1.nFadeTime),',','0[1:1]',$0D"
That works, but it seems like a really long way to do it?
The idea behind organizing your data in the manner implied by creating all these structures and/or arrays is called "virtualizing" your code. The idea that you're avoiding hard-coding everything. As an extreme example you don't create 20 button_events in code to handle 20 presets. You create one button_event that calls on an array of button channels. In the event you determine which of the buttons were pushed and from that determine which preset to send. It involves you lining up the data cells of the preset commands with the data cells of the buttons and what those buttons represent.
A good rule of thumb is - if you find yourself placing an integer value (in your case the [1]), it implies you haven't virtualized your code far enough yet. (or there is always some case where it's an out lying thing and it's just easier (lazier) to just pop it in for that special case)
Your code might look like this for example
(I broke up your long string build to two lines for ease of reading but it's still the same.
Additionally, I'd be willing to bet you could pack away that at the end of the string in your presets data base as well so you're not hard coding that little section in the presets as well. Perhaps that section is not different from one preset to another or something. Anyway, hope that helps.
e
Pointers would be nice. It is clear from AMX's attitude toward Duet that they have ZERO interest in providing support for anything marginally complicated. They won't even let you speak directly with any of the Duet programmers.
Duet has been a white elephant for some time now. It's complicated. From zero support to zero documentation (in fact the only documentation to get started won't even compile) to utilizing an already out-of-date version of JAVA, etc... It was kind of a strange implementation of what could have conceivably been a pretty cool development environment.
But, in fact, I don't think they ever intended it for us "forum types" ie: AMX Programmers. It's was really a way to get gear manufacturers to write modules for control. Most equipment manufactuers didnt want to send their expensive software engineers to learn this quirky Netlinx language. they already were spending big bucks hiring JAVA programmers. So, AMX glommed onto it via DUET, hoping the manufacturers would easily get their current programmers to also write modules.
As we all know - the problem with that idea was that, while they might be good JAVA programmers with lots of industrial engineering chops, they had no idea how an AV control system worked or why we do the things we do.
At every AMX Developers Conference I've been to we discussed the whole notion of going to some kind of more mainstream development environment. (Like JAVA, C#,MS Visual BASIC, etc...) It seems like an neat toy for us engineer types. But whenever they even approach the idea of making it so, it crashes on the rocks of having to migrate a whole bunch of people (a good chunk of us programmers) who are not 'classically' trained in modern objecct-oriented programming think and who are in many cases folks who sort just learned it on our own.
I can say, having come up from the Computer Science/Engineering world, I've found the AV world sometimes a bit scary. We AV programmers sometimes don't follow more mainstream 'best practices'; particularly in the areas of code formatting, documentation and software version management. (Let alone just fricken backing up the source code) After all - we're just turning TVs on and off... It was a good gig, I got paid.
So, while I would LOVE for us to migrate to something more mainstream (and I have no pony in that race - JAVA, C#, C++, cool by me) I really don't see our industry wanting to send all of us AV programmers to school to learn the new stuff - particularly when that same newly trained programmer would certainly now find much better paying jobs at many other manufactuers and whatnot.
LOL Yeah it's lazy AF from a programming standpoint, but when you're working in an archaic, numeric token based language, sometimes the damned number itself makes as much sense in the code, as anything else. When comparing code, I've found myself often far more willing to bend my programming to the language, than to bend the language to my programming. But that means my skill level is basically still 1980's procedural-based coding. Quite frankly bummed about the career dead-end corner I appear to painted myself into at this point.
Also, for many years now, I've been thinking / imagining about an open-source platform for AV control, basically PHP/Python with some kind of SQL backend. I've even coded up the roughest framework for it, had it running on one project for awhile. But the combination of the "No custom development, must use vendor products as-is out of the box" mantra, along with realistic constraints on my time and not-very-good programming abilities, slowly killed it. It seems like EDU market could band together and develop something like this fairly easily.
But, it's obviously not that easy, or cost effective, or perhaps it would be done already?
I was thinking there should be away to make " Preset[1].LT_Zone1.nIntensity" shorter. Pointers is what I was thinking about. I'll figure it out.
Yes, I was also thinking "0,[1:1]" could be done differently. 0,[1:itoa(variable)] variable +1 There are 4 of them.
You wouldn't see the slowness of nested structures if you are using them that way. If you use them to store lots of data that you constantly read and write to, you'll quickly notice that its much slower to access than arrays. My guess is for arrays, a lookup is just following a pointer, whereas for a nested structure, there are some calculations required to end up at the correct memory location. For XML/JSON and other formats that have a nested arrangement nested structs would be ideal, but I no longer do it that way unless the data is fairly small in size due to the speed issue. Hopefully its no longer the case with NX controllers.
Paul