Home AMX User Forum NetLinx Studio
Options

Pass a STRUCTURE into a module?

Anyone know if this is possible?

I'd like to pass a DEFINE_TYPE STRUCTURE[] into a Module that I've completed.
«1

Comments

  • Options
    Joe HebertJoe Hebert Posts: 2,159
    No can do. Sad but true. :(
    dthorson wrote:
    Anyone know if this is possible?

    I'd like to pass a DEFINE_TYPE STRUCTURE[] into a Module that I've completed.
  • Options
    dthorsondthorson Posts: 103
    Thanks Joe.

    I'm off down another coding path.
  • Options
    a_riot42a_riot42 Posts: 1,624
    But you can pass the contents of said structure. So instead of
    structure _SatRadio
    {
      integer     nGenres[20]
      integer     nStations[20]
    }  
    
    _SatRadio satRadio
    
    #define_module  'ModuleThatNeedsStruct'         mdl(satRadio)
    

    you do
    volatile integer     nGenres[20]
    volatile integer     nStations[20]
    
    #define_module  'ModuleThatNeedsStruct'         mdl(nGenres, nStations)
    
    
  • Options
    GSLogicGSLogic Posts: 562
    a_riot42 wrote:
    But you can pass the contents of said structure. you do
    volatile integer     nGenres[20]
    volatile integer     nStations[20]
    
    #define_module  'ModuleThatNeedsStruct'         mdl(nGenres, nStations)
    
    
    Most of time the STRUCTURE is duplicated and that's what creates the problem.

    DEFINE VAR
    _SatRadio SatRadio[5]; (I now have five arrays in the structure)
  • Options
    dthorsondthorson Posts: 103
    I'm actually using that approach.

    That way I can change the layout/order and graphics on the fly in code.
    I was hoping to pass the structure array to the module that runs the TP, but passing the values is working well too.
    DEFINE_TYPE
    
    STRUCTURE _sMainMenu
    {
    	CHAR		cPopName[50]		// Popup page name
    	CHAR		cPopupLabel[255]	// Main Menu/Popup display text
    	CHAR		cResourceName[50]	// Graphic name in resource manager
    	INTEGER		iListButton			// Menu List Button Channel
    	INTEGER		iIconButton			// Icon Button Channel 
    }
    
    
    NON_VOLATILE _sMainMenu sMenuItem_Laptop;
    NON_VOLATILE _sMainMenu sMenuItem_AvPresentation;
    NON_VOLATILE _sMainMenu sMenuItem_DVD;
    NON_VOLATILE _sMainMenu sMenuItem_VCR;
    NON_VOLATILE _sMainMenu sMenuItem_CableTv;
    NON_VOLATILE _sMainMenu sMenuItem_AtcLine1;
    NON_VOLATILE _sMainMenu sMenuItem_AtcLine2;
    
    NON_VOLATILE _sMainMenu sMainMenu[50]; (* User Created Main Menu Items *)
    
    
    DEFINE_START
    
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // Build Your Main Menu Here, TP Popup, Text to Display, Graphic Feedback
    //////////////////////////////////////////////////////////////////////////////////////////////////
    sMenuItem_Laptop.cPopName			=	'Laptop';
    sMenuItem_Laptop.cPopupLabel		=	'Laptop';
    sMenuItem_Laptop.cResourceName		=	'MainMenu-Laptop.png';
    
    sMenuItem_DVD.cPopName				=	'DVD';
    sMenuItem_DVD.cPopupLabel			=	'DVD';
    sMenuItem_DVD.cResourceName			=	'MainMenu-DVD Case.png';
    
    sMenuItem_VCR.cPopName				=	'VCR';
    sMenuItem_VCR.cPopupLabel			=	'VCR';
    sMenuItem_VCR.cResourceName			=	'MainMenu-VHS Tape.png';
    
    
    sMenuItem_CableTv.cPopName			=	'Cable Tv';
    sMenuItem_CableTv.cPopupLabel		=	'Cable Tv';
    sMenuItem_CableTv.cResourceName		=	'MainMenu-Satellite Dish.png';
    //////////////////////////////////////////////////////////////////////////////////////////////////
    // Build the order of the Main Menu
    //////////////////////////////////////////////////////////////////////////////////////////////////
    sMainMenu[iMenu1] = sMenuItem_Laptop
    sMainMenu[iMenu2] = sMenuItem_DVD
    sMainMenu[iMenu3] = sMenuItem_VCR
    sMainMenu[iMenu4] = sMenuItem_CableTv
    
    
  • Options
    a_riot42a_riot42 Posts: 1,624
    GSLogic wrote:
    Most of time the STRUCTURE is duplicated and that's what creates the problem.

    DEFINE VAR
    _SatRadio SatRadio[5]; (I now have five arrays in the structure)

    Don't you mean you have an array of structures with 5 elements?
    Paul
  • Options
    filpeefilpee Posts: 64
    I know its a pain and makes for more work but you could use VARIABLE_TO_STRING to encode the structure and send it to your module.

    then in your module you have to decode it using STRING_TO_VARIABLE passing the info into your structure.
    //Include file so can be used in Master Source and your module
    DEFINE_CONSTANT
    char optSendingStruct = 1
    //declare your structure
    DEFINE_TYPE
    structure _sMyStructure {
      char cAlbum[255]
      char cArtist[255]
      integer nID
    }
    
    DEFINE_FUNCTION sendStruct(_sMyStructure struct){
      char sBuffer[2048]
      long lPos
      sinteger siStatus
    
      sBuffer = "optSendingStruct"  //used so that we know what kind of data we are sending
      lPos = 2
      siStatus = Variable_To_String(struct, sBuffer, lPos)
      if (siStatus == 0){   //success
        Send_Command module, "sBuffer"
      }
    }
    
    //Master Source
    #INCLUDE 'includefile.axi'
    DEFINE_VARIABLE
    volatile _sMyStructure _sCdLibrary[255]
    DEFINE_START
    //fill your struct
    
    sendStruct (_sCdLibrary)
    
    //module file
    #INCLUDE 'includefile.axi' 
    
    DEFINE_VARIABLE
    volatile _sMyStructure _sCdLibrary[255]
    
    define_function (char str[])
    {
      long lPos
      sinteger siStatus
    
      lPos = 2
      siStatus = String_To_Variable(_sCdLibrary,str, lPos)
    
      if (siStatus <> 0){
        //flag an error
        return
      }
    } 
    
    data_event[module]
    {
      command:
      {
        switch (data.text[1]){
          case optSendingStruct: {
            setAlbumData (data.text[2])
          }
        }
      }
    }
    



    I have something similar to this working fine.
    But as you can see its a hassle to implement but does allow you the option of passing a heap of data to a module on the fly.


    credits to Jeff Coffler and his SlimServerMod program which is where I found this technique.
  • Options
    GSLogicGSLogic Posts: 562
    a_riot42 wrote:
    Don't you mean you have an array of structures with 5 elements?
    Paul

    I think of structures like a java/class (I know they aren't), once you build one with all your arrays inside, you can duplicate them. When you change the main structure, it changes all of the copies you made.

    I've found the best way to get around modules and structures is to save all data to an XML file. The advantage to this is, if the master ever goes down you just upload the XML files and all the user data is back.
    My resi program lets the user store/change all event timers which include lights/thermo/sprinklers/shades/music events/etc - yes, I have these XML files emailed to me monthly just to have a recovery point.
  • Options
    no available
    dthorson wrote:
    Anyone know if this is possible?

    I'd like to pass a DEFINE_TYPE STRUCTURE[] into a Module that I've completed.


    the best way to use a structure in a module, is to create the type on the main program, and on the module. Then you just have to passe every array or variable into your module declaration. It's working fine, and you can use structure on you module...
  • Options
    AMXJeffAMXJeff Posts: 450
    FILPEE has the right method... STRING_TO_VARIABLE VARIABLE_TO_STRING are the perferred method!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  • Options
    a_riot42a_riot42 Posts: 1,624
    AMXJeff wrote:
    FILPEE has the right method... STRING_TO_VARIABLE VARIABLE_TO_STRING are the perferred method!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


    Will that work? I would think that every time a variable in the structure changes you would need to manually update the other structure by doing the variable to string thing. Is this not the case? If it is that adds a bunch of extra processing that needs to be kept track of in case it gets out of sync.
    Paul
  • Options
    DHawthorneDHawthorne Posts: 4,584
    a_riot42 wrote:
    Will that work? I would think that every time a variable in the structure changes you would need to manually update the other structure by doing the variable to string thing. Is this not the case? If it is that adds a bunch of extra processing that needs to be kept track of in case it gets out of sync.
    Paul

    I think the structure has to be defined identically in the main program and the module for the to work ... which, of course, eliminates the ability to change the structure on the fly.

    I prefer to send components of the structure as module parameters, then populate them in the module DEFINE_START. It's not ideal, but seems to me to fit the bill best in terms of readability and ease of use.
  • Options
    a_riot42a_riot42 Posts: 1,624
    DHawthorne wrote:
    I think the structure has to be defined identically in the main program and the module for the to work ... which, of course, eliminates the ability to change the structure on the fly.

    I prefer to send components of the structure as module parameters, then populate them in the module DEFINE_START. It's not ideal, but seems to me to fit the bill best in terms of readability and ease of use.


    That's what I thought. Any changes on the fly will not be reflected in the other structures until you update them. I figure all the structure does in encapsulate a few variables anyway, so why not just use arrays? Writing variables to a file sounds like a good idea for some infrequently changing data, but I would think the constant I/O would slow things down if the data changed frequently like volume. I think I will just stick to arrays for now until they allow passing a structure to a module.
    Paul
  • Options
    AMXJeffAMXJeff Posts: 450
    VARIABLE_TO_STRING STRING_TO_VARIABLE is Fast

    You can also update the information by passing it into the module. Outside the module just keep the passed in char array up to date using VARIABLE_TO_STRING. Inside the module just do a STRING_TO_VARIABLE before you use and trust the data.

    MODULE_NAME='Structure Test" (CHAR cEncodedData[])
  • Options
    GSLogicGSLogic Posts: 562
    a_riot42 wrote:
    I figure all the structure does in encapsulate a few variables anyway, so why not just use arrays? Writing variables to a file sounds like a good idea for some infrequently changing data, but I would think the constant I/O would slow things down if the data changed frequently like volume. I think I will just stick to arrays for now until they allow passing a structure to a module.
    Paul
    You'd have to pass all these variables to a module and then trying to keep track of them in the debug window is a pain - and this is only for the audio section. I use a global structure to track all the touchpanels to see which TPs are viewing which section, so it makes it very difficult to create quality modules that work in BIG systems. The idea of defining a new module for ever touchpanel doesn't work all the time and it's not very good practice. It sure would open doors if AMX added the ability to send structures to modules.
    structure _AD_out
      {
    	char	 cLoc[24];		// output location name
    	integer  nSrc;			// source selected
    	sinteger snVol;			// output volume
    	sinteger snTR;			// treble
    	sinteger snBS;			// bass
    	slong 	 snEQ[10];		// 10 band eq
    	integer  nMute;			// output mute status
    	integer  nPanel[nTOTAL_PANELS];	// hold all panels viewing this output
    	integer  nLockOut;		// lockout others from changing your music
      };
    
  • Options
    AMXJeffAMXJeff Posts: 450
    It will be impossible to add that ablity. Modules are pre-compiled prior to the main code being compiled. The structures that you all want to pass in are declared in the main code. The module has no knowledge of it prior to its compile time. Modules are ment to be portable, and not locked into a certain project.

    There is absolutly no reason why STRING_TO_VARIABLE/VARIABLE_TO_STRING is not the solution to the problem... It works great, end of soap box....
  • Options
    DHawthorneDHawthorne Posts: 4,584
    AMXJeff wrote:
    There is absolutly no reason why STRING_TO_VARIABLE/VARIABLE_TO_STRING is not the solution to the problem... It works great, end of soap box....

    Actually, there is one very big reason why it doesn't always provide a good solution: you still must define the structure identically in both the calling program and the module being called. The original poster refers to exactly that; he wanted the ability to change the structure members in the main code and propagate it to the module; if your module is pre-compiled, you cannot in any way, shape or form do this ... both the calling program and the module must be recompiled.

    Now if the marshaling protocols passed the metadata necessary to actually create the structure and define it in the module, it would work, but they do not.
  • Options
    AMXJeffAMXJeff Posts: 450
    Agreed - but the filpee solution provided the method for doing it correctly. Include file that you include in both the Main code and the Module code. The structure/size of array must be declared in that include file and used correctly in both location.

    Even though that is pain, it is still better then passing all that information into the module as seperate arrays parameters. Small price to be pay for the correct solution.
  • Options
    GSLogicGSLogic Posts: 562
    AMXJeff wrote:
    There is absolutly no reason why STRING_TO_VARIABLE/VARIABLE_TO_STRING is not the solution to the problem... It works great, end of soap box....
    This method won't keep the modules structure updated with the data from the main.axs.
  • Options
    Joe HebertJoe Hebert Posts: 2,159
    V2S and S2V
    AMXJeff wrote:
    There is absolutly no reason why STRING_TO_VARIABLE/VARIABLE_TO_STRING is not the solution to the problem... It works great, end of soap box....
    GSLogic wrote:
    This method won't keep the modules structure updated with the data from the main.axs.
    Sure it will. As AMXJeff stated earlier:
    AMXJeff wrote:
    Outside the module just keep the passed in char array up to date using VARIABLE_TO_STRING. Inside the module just do a STRING_TO_VARIABLE before you use and trust the data.

    It works perfectly! Here?s an example where the main program or the module can alter the data and they will both stay in sync. I chose to pass the encoded string in as a parameter to the module instead of the SEND_COMMAND method that filpee demonstrated. I believe SEND_COMMAND is limited to about 128 bytes (and SEND_STRING is somewhere around 2000 bytes) so if you want to pass heaps of data back and forth at one time I don?t think the SEND_COMMAND route will suffice. If I?m wrong someone please correct me. Anyway here?s the code:
    PROGRAM_NAME='V2S_S2VTest'
    
    #include 'Include'
    
    DEFINE_DEVICE
    
    dvTP 		= 10001:1:0
    
    vdvModule	= 33001:1:0
    
    DEFINE_VARIABLE
    
    //encoded string to be shared between main and module
    CHAR cMainBinary[256]
    
    DEFINE_START
    
    //start off by filling some data in
    sStruct[1].A = 1
    sStruct[1].B = 2
    sStruct[2].A = 21
    sStruct[2].B = 22
    
    ///values changed so encode
    VARIABLE_TO_STRING(sStruct, cMainBinary, 1) 
         
    DEFINE_MODULE 'Module' mdlTest (vdvModule,cMainBinary)
    
    DEFINE_EVENT
    
    //print current main program values
    BUTTON_EVENT[dvTP,1] { 
    
       PUSH: {
          //before using validate by decoding first
          STRING_TO_VARIABLE(sStruct, cMainBinary, 1)
          SEND_STRING 0, "'Inside Main A1=',ITOA(sStruct[1].A)"
          SEND_STRING 0, "'Inside Main B1=',ITOA(sStruct[1].B)"
          SEND_STRING 0, "'Inside Main A2=',ITOA(sStruct[2].A)"
          SEND_STRING 0, "'Inside Main B2=',ITOA(sStruct[2].B)"
       
       }
    }
    
    //tell module to print values
    BUTTON_EVENT[dvTP,2] {
       
       PUSH: {
          PULSE[vdvModule,1]
       }
    }
    
    //change current value in main program
    BUTTON_EVENT[dvTP,3] { 
    
       PUSH: {
          SEND_STRING 0, 'Main program is changing values'
          sStruct[1].A = 3
          sStruct[1].B = 4
          sStruct[2].A = 23
          sStruct[2].B = 24
           //values changed so encode
          VARIABLE_TO_STRING(sStruct, cMainBinary, 1)
       }
    }
    
    //tell module to change values
    BUTTON_EVENT[dvTP,4] { 
       
       PUSH: {
          PULSE[vdvModule,2]
       }
    }
    
    
    PROGRAM_NAME='Include'
    
    DEFINE_TYPE
    
    STRUCT _sStruct {
    
       INTEGER a
       INTEGER b
    }
    
    DEFINE_VARIABLE
    
    _sStruct sStruct[2]
    
    
    MODULE_NAME='Module' (DEV vdvMod,CHAR cModuleBinary[])
    
    #include 'Include'
    
    DEFINE_EVENT
    
    //print current values
    CHANNEL_EVENT[vdvMod,1] {
    
       ON: {
          //before using validate by decoding first
          STRING_TO_VARIABLE(sStruct, cModuleBinary, 1)
          SEND_STRING 0, "'Inside Module A1=',ITOA(sStruct[1].A)"
          SEND_STRING 0, "'Inside Module B1=',ITOA(sStruct[1].B)"
          SEND_STRING 0, "'Inside Module A2=',ITOA(sStruct[2].A)"
          SEND_STRING 0, "'Inside Module B2=',ITOA(sStruct[2].B)"
       }
    }
    
    //change current values in module
    CHANNEL_EVENT[vdvMod,2] {
    
       ON: {
          SEND_STRING 0, 'Module is changing values'
          sStruct[1].A = 5
          sStruct[1].B = 6
          sStruct[2].A = 25
          sStruct[2].B = 26
          //values changed so encode    
          VARIABLE_TO_STRING(sStruct, cModuleBinary, 1)
          
       }
    }
    

    After a Button 1 Push:
    Line      1 :: Inside Main A1=1 - 01:15:13
    Line      2 :: Inside Main B1=2 - 01:15:13
    Line      3 :: Inside Main A2=21 - 01:15:13
    Line      4 :: Inside Main B2=22 - 01:15:13
    

    After a Button 2 Push:
    Line      5 :: Inside Module A1=1 - 01:15:16
    Line      6 :: Inside Module B1=2 - 01:15:16
    Line      7 :: Inside Module A2=21 - 01:15:16
    Line      8 :: Inside Module B2=22 - 01:15:16
    

    After a Button 3 Push
    Line      9 :: Main program is changing values - 01:15:19
    

    After a Button 1 Push:
    Line     10 :: Inside Main A1=3 - 01:15:21
    Line     11 :: Inside Main B1=4 - 01:15:21
    Line     12 :: Inside Main A2=23 - 01:15:21
    Line     13 :: Inside Main B2=24 - 01:15:21
    

    After a Button 2 Push:
    Line     14 :: Inside Module A1=3 - 01:15:23
    Line     15 :: Inside Module B1=4 - 01:15:23
    Line     16 :: Inside Module A2=23 - 01:15:23
    Line     17 :: Inside Module B2=24 - 01:15:23
    

    After a Button 4 Push
    Line     18 :: Module is changing values - 01:15:25
    

    After a Button 1 Push:
    Line     19 :: Inside Main A1=5 - 01:15:27
    Line     20 :: Inside Main B1=6 - 01:15:27
    Line     21 :: Inside Main A2=25 - 01:15:27
    Line     22 :: Inside Main B2=26 - 01:15:27
    

    After a Button 2 Push:
    Line     23 :: Inside Module A1=5 - 01:15:30
    Line     24 :: Inside Module B1=6 - 01:15:30
    Line     25 :: Inside Module A2=25 - 01:15:30
    Line     26 :: Inside Module B2=26 - 01:15:30
    

    Thanks for your insight filpee and AMXJeff! Your posts opened new doors for me. It?s a beautiful thing! :)

    If anyone wants to try the code without cutting and pasting, I attached the project file.
  • Options
    AMXJeffAMXJeff Posts: 450
    Thanks Joe for taking the time to do the testing. Hopefully this will help everyone!!!!!!

    FYI: Send_Commands to Virtual Devices is at 2000 bytes as well. But I always pass the Encoded Array into the module, it is just cleaner. Good Job!!!!!!!!!!!!!
  • Options
    a_riot42a_riot42 Posts: 1,624
    Joe Hebert wrote:
    Sure it will. As AMXJeff stated earlier:
    It works perfectly! Here?s an example where the main program or the module can alter the data and they will both stay in sync.

    The reason your structure is staying in sync is because you are continually syncing them in the code after any modification. That's cheating! :)
    What myself and I think others were hoping for is a method where there is no manual synchronization required. If you could pass a structure to a module, so that the main code and module code had the same copy of the structure, simply assigning a value to a structures members would keep them in sync because there is only one copy. In your code you have two copies and are continually syncing them after any modification. No doubt this works, but I would rather not have to try and sync everything up like that. What if you had 100 structures? Then it starts to become rather tedious to keep them synchronized manually.
    In most other programming languages like C for instance, you can pass a pointer to a structure to a function so that both the calling code and client code are looking at the same memory and no synchronization is required. I think that is the functionality that Netlinx is sorely missing.
    Paul
  • Options
    DHawthorneDHawthorne Posts: 4,584
    Yes, we want pointers!
  • Options
    AMXJeffAMXJeff Posts: 450
    I would not hold your breath for pointers!!!! You will all turn blue and pass out!!!!! Passing parameters by reference is all you have.
  • Options
    a_riot42a_riot42 Posts: 1,624
    AMXJeff wrote:
    I would not hold your breath for pointers!!!! You will all turn blue and pass out!!!!! Passing parameters by reference is all you have.

    A parameter passed by reference is a pointer essentially. All variables in Netlinx are passed by reference, with the odd exception of passing structures to modules, which you just can't do no way no how.
    Paul
  • Options
    AMXJeffAMXJeff Posts: 450
    It is not that you can't pass structure to modules. You can pass these structures DEVCHAN, DEV, DEVLEV etc... You just can't pass user defined types...
  • Options
    a_riot42a_riot42 Posts: 1,624
    AMXJeff wrote:
    It is not that you can't pass structure to modules. You can pass these structures DEVCHAN, DEV, DEVLEV etc... You just can't pass user defined types...

    So how does that relate to what you posted above about modules not having that capability because they are pre-compiled?
    Paul
  • Options
    AMXJeffAMXJeff Posts: 450
    I was just stating the reason why you will never see that feature in NetLinx. It can never work...
  • Options
    a_riot42a_riot42 Posts: 1,624
    AMXJeff wrote:
    You can pass these structures DEVCHAN, DEV, DEVLEV etc...
    AMXJeff wrote:
    I was just stating the reason why you will never see that feature in NetLinx. It can never work...

    Sorry to be dense but I don't understand how both these things can be true. If you can pass a DEV structure to a module then you can pass a structure to a module. Netlinx just doesn't allow user defined structures to be passed to modules. This would seem to indicate that it isn't impossible to pass user defined structures due to the precompilation of modules, it just hasn't been implemented.
    Paul
  • Options
    AMXJeffAMXJeff Posts: 450
    Both statements are true...

    DEV, DEVCHAN and DEVLEV are not user defined Structures, they are Native Structures to the NetLinx language. The Module knows about them Long before Line 1 of the NetLinx Module code.
Sign In or Register to comment.